Mercurial > public > mercurial-scm > hg
comparison hgext/extdiff.py @ 2333:de0c05afa511
new extension: extdiff. allows to use external diff program.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Sun, 21 May 2006 23:39:07 -0700 |
parents | |
children | 391c5d0f9ef3 |
comparison
equal
deleted
inserted
replaced
2331:953dbfb2824c | 2333:de0c05afa511 |
---|---|
1 # extdiff.py - external diff program support for mercurial | |
2 # | |
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com> | |
4 # | |
5 # This software may be used and distributed according to the terms | |
6 # of the GNU General Public License, incorporated herein by reference. | |
7 # | |
8 # allow to use external programs to compare revisions, or revision | |
9 # with working dir. program is called with two arguments: paths to | |
10 # directories containing snapshots of files to compare. | |
11 # | |
12 # to enable: | |
13 # | |
14 # [extensions] | |
15 # hgext.extdiff = | |
16 # | |
17 # also allows to configure new diff commands, so you do not need to | |
18 # type "hg extdiff -p kdiff3" always. | |
19 # | |
20 # [extdiff] | |
21 # # add new command called vdiff, runs kdiff3 | |
22 # cmd.vdiff = kdiff3 | |
23 # # add new command called meld, runs meld (no need to name twice) | |
24 # cmd.meld = | |
25 # | |
26 # you can use -I/-X and list of file or directory names like normal | |
27 # "hg diff" command. extdiff makes snapshots of only needed files, so | |
28 # compare program will be fast. | |
29 | |
30 from mercurial.demandload import demandload | |
31 from mercurial.i18n import gettext as _ | |
32 from mercurial.node import * | |
33 demandload(globals(), 'mercurial:commands,util os shutil tempfile') | |
34 | |
35 def dodiff(ui, repo, diffcmd, pats, opts): | |
36 def snapshot_node(files, node): | |
37 '''snapshot files as of some revision''' | |
38 changes = repo.changelog.read(node) | |
39 mf = repo.manifest.read(changes[0]) | |
40 dirname = '%s.%s' % (os.path.basename(repo.root), short(node)) | |
41 base = os.path.join(tmproot, dirname) | |
42 os.mkdir(base) | |
43 if not ui.quiet: | |
44 ui.write_err(_('making snapshot of %d files from rev %s\n') % | |
45 (len(files), short(node))) | |
46 for fn in files: | |
47 wfn = util.pconvert(fn) | |
48 ui.note(' %s\n' % wfn) | |
49 dest = os.path.join(base, wfn) | |
50 destdir = os.path.dirname(dest) | |
51 if not os.path.isdir(destdir): | |
52 os.makedirs(destdir) | |
53 repo.wwrite(wfn, repo.file(fn).read(mf[fn]), open(dest, 'w')) | |
54 return dirname | |
55 | |
56 def snapshot_wdir(files): | |
57 '''snapshot files from working directory. | |
58 if not using snapshot, -I/-X does not work and recursive diff | |
59 in tools like kdiff3 and meld displays too many files.''' | |
60 dirname = os.path.basename(repo.root) | |
61 base = os.path.join(tmproot, dirname) | |
62 os.mkdir(base) | |
63 if not ui.quiet: | |
64 ui.write_err(_('making snapshot of %d files from working dir\n') % | |
65 (len(files))) | |
66 for fn in files: | |
67 wfn = util.pconvert(fn) | |
68 ui.note(' %s\n' % wfn) | |
69 dest = os.path.join(base, wfn) | |
70 destdir = os.path.dirname(dest) | |
71 if not os.path.isdir(destdir): | |
72 os.makedirs(destdir) | |
73 fp = open(dest, 'w') | |
74 for chunk in util.filechunkiter(repo.wopener(wfn)): | |
75 fp.write(chunk) | |
76 return dirname | |
77 | |
78 node1, node2 = commands.revpair(ui, repo, opts['rev']) | |
79 files, matchfn, anypats = commands.matchpats(repo, pats, opts) | |
80 modified, added, removed, deleted, unknown = repo.changes( | |
81 node1, node2, files, match=matchfn) | |
82 if not (modified or added or removed): | |
83 return 0 | |
84 | |
85 tmproot = tempfile.mkdtemp(prefix='extdiff.') | |
86 try: | |
87 dir1 = snapshot_node(modified + removed, node1) | |
88 if node2: | |
89 dir2 = snapshot_node(modified + added, node2) | |
90 else: | |
91 dir2 = snapshot_wdir(modified + added) | |
92 util.system('%s %s "%s" "%s"' % | |
93 (diffcmd, ' '.join(opts['option']), dir1, dir2), | |
94 cwd=tmproot) | |
95 return 1 | |
96 finally: | |
97 ui.note(_('cleaning up temp directory\n')) | |
98 shutil.rmtree(tmproot) | |
99 | |
100 def extdiff(ui, repo, *pats, **opts): | |
101 '''use external program to diff repository (or selected files) | |
102 | |
103 Show differences between revisions for the specified files, using | |
104 an external program. The default program used is "diff -Pnru". | |
105 To select a different program, use the -p option. The program | |
106 will be passed the names of two directories to compare. To pass | |
107 additional options to the program, use the -o option. These will | |
108 be passed before the names of the directories to compare. | |
109 | |
110 When two revision arguments are given, then changes are | |
111 shown between those revisions. If only one revision is | |
112 specified then that revision is compared to the working | |
113 directory, and, when no revisions are specified, the | |
114 working directory files are compared to its parent.''' | |
115 return dodiff(ui, repo, opts['program'] or 'diff -Npru', pats, opts) | |
116 | |
117 cmdtable = { | |
118 "extdiff": | |
119 (extdiff, | |
120 [('p', 'program', '', _('comparison program to run')), | |
121 ('o', 'option', [], _('pass option to comparison program')), | |
122 ('r', 'rev', [], _('revision')), | |
123 ('I', 'include', [], _('include names matching the given patterns')), | |
124 ('X', 'exclude', [], _('exclude names matching the given patterns'))], | |
125 _('hg extdiff [OPT]... [FILE]...')), | |
126 } | |
127 | |
128 def uisetup(ui): | |
129 for cmd, path in ui.configitems('extdiff'): | |
130 if not cmd.startswith('cmd.'): continue | |
131 cmd = cmd[4:] | |
132 if not path: path = cmd | |
133 def save(cmd, path): | |
134 '''use closure to save diff command to use''' | |
135 def mydiff(ui, repo, *pats, **opts): | |
136 return dodiff(ui, repo, path, pats, opts) | |
137 mydiff.__doc__ = '''use %s to diff repository (or selected files) | |
138 | |
139 Show differences between revisions for the specified | |
140 files, using the %s program. | |
141 | |
142 When two revision arguments are given, then changes are | |
143 shown between those revisions. If only one revision is | |
144 specified then that revision is compared to the working | |
145 directory, and, when no revisions are specified, the | |
146 working directory files are compared to its parent.''' % (cmd, cmd) | |
147 return mydiff | |
148 cmdtable[cmd] = (save(cmd, path), | |
149 cmdtable['extdiff'][1][1:], | |
150 _('hg %s [OPT]... [FILE]...') % cmd) |