##// END OF EJS Templates
extdiff: wrap docstrings at 70 characters
Martin Geisler -
r9257:50ebe884 default
parent child Browse files
Show More
@@ -1,226 +1,228 b''
1 1 # extdiff.py - external diff program support for mercurial
2 2 #
3 3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2, incorporated herein by reference.
7 7
8 8 '''command to allow external programs to compare revisions
9 9
10 The `extdiff' Mercurial extension allows you to use external programs to
11 compare revisions, or revision with working directory. The external diff
12 programs are called with a configurable set of options and two non-option
13 arguments: paths to directories containing snapshots of files to compare.
10 The `extdiff' Mercurial extension allows you to use external programs
11 to compare revisions, or revision with working directory. The external
12 diff programs are called with a configurable set of options and two
13 non-option arguments: paths to directories containing snapshots of
14 files to compare.
14 15
15 The `extdiff' extension also allows to configure new diff commands, so you do
16 not need to type "hg extdiff -p kdiff3" always. ::
16 The `extdiff' extension also allows to configure new diff commands, so
17 you do not need to type "hg extdiff -p kdiff3" always. ::
17 18
18 19 [extdiff]
19 20 # add new command that runs GNU diff(1) in 'context diff' mode
20 21 cdiff = gdiff -Nprc5
21 22 ## or the old way:
22 23 #cmd.cdiff = gdiff
23 24 #opts.cdiff = -Nprc5
24 25
25 26 # add new command called vdiff, runs kdiff3
26 27 vdiff = kdiff3
27 28
28 29 # add new command called meld, runs meld (no need to name twice)
29 30 meld =
30 31
31 # add new command called vimdiff, runs gvimdiff with DirDiff plugin (see
32 # http://www.vim.org/scripts/script.php?script_id=102) Non English user, be
33 # sure to put "let g:DirDiffDynamicDiffText = 1" in your .vimrc
32 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
33 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
34 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
35 # your .vimrc
34 36 vimdiff = gvim -f '+next' '+execute "DirDiff" argv(0) argv(1)'
35 37
36 You can use -I/-X and list of file or directory names like normal "hg diff"
37 command. The `extdiff' extension makes snapshots of only needed files, so
38 running the external diff program will actually be pretty fast (at least
39 faster than having to compare the entire tree).
38 You can use -I/-X and list of file or directory names like normal "hg
39 diff" command. The `extdiff' extension makes snapshots of only needed
40 files, so running the external diff program will actually be pretty
41 fast (at least faster than having to compare the entire tree).
40 42 '''
41 43
42 44 from mercurial.i18n import _
43 45 from mercurial.node import short
44 46 from mercurial import cmdutil, util, commands
45 47 import os, shlex, shutil, tempfile
46 48
47 49 def snapshot(ui, repo, files, node, tmproot):
48 50 '''snapshot files as of some revision
49 51 if not using snapshot, -I/-X does not work and recursive diff
50 52 in tools like kdiff3 and meld displays too many files.'''
51 53 dirname = os.path.basename(repo.root)
52 54 if dirname == "":
53 55 dirname = "root"
54 56 if node is not None:
55 57 dirname = '%s.%s' % (dirname, short(node))
56 58 base = os.path.join(tmproot, dirname)
57 59 os.mkdir(base)
58 60 if node is not None:
59 61 ui.note(_('making snapshot of %d files from rev %s\n') %
60 62 (len(files), short(node)))
61 63 else:
62 64 ui.note(_('making snapshot of %d files from working directory\n') %
63 65 (len(files)))
64 66 wopener = util.opener(base)
65 67 fns_and_mtime = []
66 68 ctx = repo[node]
67 69 for fn in files:
68 70 wfn = util.pconvert(fn)
69 71 if not wfn in ctx:
70 72 # skipping new file after a merge ?
71 73 continue
72 74 ui.note(' %s\n' % wfn)
73 75 dest = os.path.join(base, wfn)
74 76 fctx = ctx[wfn]
75 77 data = repo.wwritedata(wfn, fctx.data())
76 78 if 'l' in fctx.flags():
77 79 wopener.symlink(data, wfn)
78 80 else:
79 81 wopener(wfn, 'w').write(data)
80 82 if 'x' in fctx.flags():
81 83 util.set_flags(dest, False, True)
82 84 if node is None:
83 85 fns_and_mtime.append((dest, repo.wjoin(fn), os.path.getmtime(dest)))
84 86 return dirname, fns_and_mtime
85 87
86 88 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
87 89 '''Do the actuall diff:
88 90
89 91 - copy to a temp structure if diffing 2 internal revisions
90 92 - copy to a temp structure if diffing working revision with
91 93 another one and more than 1 file is changed
92 94 - just invoke the diff for a single file in the working dir
93 95 '''
94 96
95 97 revs = opts.get('rev')
96 98 change = opts.get('change')
97 99
98 100 if revs and change:
99 101 msg = _('cannot specify --rev and --change at the same time')
100 102 raise util.Abort(msg)
101 103 elif change:
102 104 node2 = repo.lookup(change)
103 105 node1 = repo[node2].parents()[0].node()
104 106 else:
105 107 node1, node2 = cmdutil.revpair(repo, revs)
106 108
107 109 matcher = cmdutil.match(repo, pats, opts)
108 110 modified, added, removed = repo.status(node1, node2, matcher)[:3]
109 111 if not (modified or added or removed):
110 112 return 0
111 113
112 114 tmproot = tempfile.mkdtemp(prefix='extdiff.')
113 115 dir2root = ''
114 116 try:
115 117 # Always make a copy of node1
116 118 dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0]
117 119 changes = len(modified) + len(removed) + len(added)
118 120
119 121 # If node2 in not the wc or there is >1 change, copy it
120 122 if node2 or changes > 1:
121 123 dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot)
122 124 else:
123 125 # This lets the diff tool open the changed file directly
124 126 dir2 = ''
125 127 dir2root = repo.root
126 128 fns_and_mtime = []
127 129
128 130 # If only one change, diff the files instead of the directories
129 131 if changes == 1 :
130 132 if len(modified):
131 133 dir1 = os.path.join(dir1, util.localpath(modified[0]))
132 134 dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0]))
133 135 elif len(removed) :
134 136 dir1 = os.path.join(dir1, util.localpath(removed[0]))
135 137 dir2 = os.devnull
136 138 else:
137 139 dir1 = os.devnull
138 140 dir2 = os.path.join(dir2root, dir2, util.localpath(added[0]))
139 141
140 142 cmdline = ('%s %s %s %s' %
141 143 (util.shellquote(diffcmd), ' '.join(diffopts),
142 144 util.shellquote(dir1), util.shellquote(dir2)))
143 145 ui.debug(_('running %r in %s\n') % (cmdline, tmproot))
144 146 util.system(cmdline, cwd=tmproot)
145 147
146 148 for copy_fn, working_fn, mtime in fns_and_mtime:
147 149 if os.path.getmtime(copy_fn) != mtime:
148 150 ui.debug(_('file changed while diffing. '
149 151 'Overwriting: %s (src: %s)\n') % (working_fn, copy_fn))
150 152 util.copyfile(copy_fn, working_fn)
151 153
152 154 return 1
153 155 finally:
154 156 ui.note(_('cleaning up temp directory\n'))
155 157 shutil.rmtree(tmproot)
156 158
157 159 def extdiff(ui, repo, *pats, **opts):
158 160 '''use external program to diff repository (or selected files)
159 161
160 Show differences between revisions for the specified files, using an
161 external program. The default program used is diff, with default options
162 "-Npru".
162 Show differences between revisions for the specified files, using
163 an external program. The default program used is diff, with
164 default options "-Npru".
163 165
164 To select a different program, use the -p/--program option. The program
165 will be passed the names of two directories to compare. To pass additional
166 options to the program, use -o/--option. These will be passed before the
167 names of the directories to compare.
166 To select a different program, use the -p/--program option. The
167 program will be passed the names of two directories to compare. To
168 pass additional options to the program, use -o/--option. These
169 will be passed before the names of the directories to compare.
168 170
169 When two revision arguments are given, then changes are shown between
170 those revisions. If only one revision is specified then that revision is
171 compared to the working directory, and, when no revisions are specified,
172 the working directory files are compared to its parent.
173 '''
171 When two revision arguments are given, then changes are shown
172 between those revisions. If only one revision is specified then
173 that revision is compared to the working directory, and, when no
174 revisions are specified, the working directory files are compared
175 to its parent.'''
174 176 program = opts['program'] or 'diff'
175 177 if opts['program']:
176 178 option = opts['option']
177 179 else:
178 180 option = opts['option'] or ['-Npru']
179 181 return dodiff(ui, repo, program, option, pats, opts)
180 182
181 183 cmdtable = {
182 184 "extdiff":
183 185 (extdiff,
184 186 [('p', 'program', '', _('comparison program to run')),
185 187 ('o', 'option', [], _('pass option to comparison program')),
186 188 ('r', 'rev', [], _('revision')),
187 189 ('c', 'change', '', _('change made by revision')),
188 190 ] + commands.walkopts,
189 191 _('hg extdiff [OPT]... [FILE]...')),
190 192 }
191 193
192 194 def uisetup(ui):
193 195 for cmd, path in ui.configitems('extdiff'):
194 196 if cmd.startswith('cmd.'):
195 197 cmd = cmd[4:]
196 198 if not path: path = cmd
197 199 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
198 200 diffopts = diffopts and [diffopts] or []
199 201 elif cmd.startswith('opts.'):
200 202 continue
201 203 else:
202 204 # command = path opts
203 205 if path:
204 206 diffopts = shlex.split(path)
205 207 path = diffopts.pop(0)
206 208 else:
207 209 path, diffopts = cmd, []
208 210 def save(cmd, path, diffopts):
209 211 '''use closure to save diff command to use'''
210 212 def mydiff(ui, repo, *pats, **opts):
211 213 return dodiff(ui, repo, path, diffopts, pats, opts)
212 214 mydiff.__doc__ = _('''\
213 215 use %(path)s to diff repository (or selected files)
214 216
215 217 Show differences between revisions for the specified files, using the
216 218 %(path)s program.
217 219
218 220 When two revision arguments are given, then changes are shown between
219 221 those revisions. If only one revision is specified then that revision is
220 222 compared to the working directory, and, when no revisions are specified,
221 223 the working directory files are compared to its parent.\
222 224 ''') % dict(path=util.uirepr(path))
223 225 return mydiff
224 226 cmdtable[cmd] = (save(cmd, path, diffopts),
225 227 cmdtable['extdiff'][1][1:],
226 228 _('hg %s [OPTION]... [FILE]...') % cmd)
General Comments 0
You need to be logged in to leave comments. Login now