##// END OF EJS Templates
extdiff: isolate path variable of saved command to independent paragraph...
Yuya Nishihara -
r29723:91b2f217 default
parent child Browse files
Show More
@@ -1,390 +1,392 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 or any later version.
7 7
8 8 '''command to allow external programs to compare revisions
9 9
10 10 The extdiff Mercurial extension allows you to use external programs
11 11 to compare revisions, or revision with working directory. The external
12 12 diff programs are called with a configurable set of options and two
13 13 non-option arguments: paths to directories containing snapshots of
14 14 files to compare.
15 15
16 16 The extdiff extension also allows you to configure new diff commands, so
17 17 you do not need to type :hg:`extdiff -p kdiff3` always. ::
18 18
19 19 [extdiff]
20 20 # add new command that runs GNU diff(1) in 'context diff' mode
21 21 cdiff = gdiff -Nprc5
22 22 ## or the old way:
23 23 #cmd.cdiff = gdiff
24 24 #opts.cdiff = -Nprc5
25 25
26 26 # add new command called meld, runs meld (no need to name twice). If
27 27 # the meld executable is not available, the meld tool in [merge-tools]
28 28 # will be used, if available
29 29 meld =
30 30
31 31 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
32 32 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
33 33 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
34 34 # your .vimrc
35 35 vimdiff = gvim -f "+next" \\
36 36 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
37 37
38 38 Tool arguments can include variables that are expanded at runtime::
39 39
40 40 $parent1, $plabel1 - filename, descriptive label of first parent
41 41 $child, $clabel - filename, descriptive label of child revision
42 42 $parent2, $plabel2 - filename, descriptive label of second parent
43 43 $root - repository root
44 44 $parent is an alias for $parent1.
45 45
46 46 The extdiff extension will look in your [diff-tools] and [merge-tools]
47 47 sections for diff tool arguments, when none are specified in [extdiff].
48 48
49 49 ::
50 50
51 51 [extdiff]
52 52 kdiff3 =
53 53
54 54 [diff-tools]
55 55 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
56 56
57 57 You can use -I/-X and list of file or directory names like normal
58 58 :hg:`diff` command. The extdiff extension makes snapshots of only
59 59 needed files, so running the external diff program will actually be
60 60 pretty fast (at least faster than having to compare the entire tree).
61 61 '''
62 62
63 63 from __future__ import absolute_import
64 64
65 65 import os
66 66 import re
67 67 import shlex
68 68 import shutil
69 69 import tempfile
70 70 from mercurial.i18n import _
71 71 from mercurial.node import (
72 72 nullid,
73 73 short,
74 74 )
75 75 from mercurial import (
76 76 archival,
77 77 cmdutil,
78 78 commands,
79 79 error,
80 80 filemerge,
81 81 scmutil,
82 82 util,
83 83 )
84 84
85 85 cmdtable = {}
86 86 command = cmdutil.command(cmdtable)
87 87 # Note for extension authors: ONLY specify testedwith = 'internal' for
88 88 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
89 89 # be specifying the version(s) of Mercurial they are tested with, or
90 90 # leave the attribute unspecified.
91 91 testedwith = 'internal'
92 92
93 93 def snapshot(ui, repo, files, node, tmproot, listsubrepos):
94 94 '''snapshot files as of some revision
95 95 if not using snapshot, -I/-X does not work and recursive diff
96 96 in tools like kdiff3 and meld displays too many files.'''
97 97 dirname = os.path.basename(repo.root)
98 98 if dirname == "":
99 99 dirname = "root"
100 100 if node is not None:
101 101 dirname = '%s.%s' % (dirname, short(node))
102 102 base = os.path.join(tmproot, dirname)
103 103 os.mkdir(base)
104 104 fns_and_mtime = []
105 105
106 106 if node is not None:
107 107 ui.note(_('making snapshot of %d files from rev %s\n') %
108 108 (len(files), short(node)))
109 109 else:
110 110 ui.note(_('making snapshot of %d files from working directory\n') %
111 111 (len(files)))
112 112
113 113 if files:
114 114 repo.ui.setconfig("ui", "archivemeta", False)
115 115
116 116 archival.archive(repo, base, node, 'files',
117 117 matchfn=scmutil.matchfiles(repo, files),
118 118 subrepos=listsubrepos)
119 119
120 120 for fn in sorted(files):
121 121 wfn = util.pconvert(fn)
122 122 ui.note(' %s\n' % wfn)
123 123
124 124 if node is None:
125 125 dest = os.path.join(base, wfn)
126 126
127 127 fns_and_mtime.append((dest, repo.wjoin(fn),
128 128 os.lstat(dest).st_mtime))
129 129 return dirname, fns_and_mtime
130 130
131 131 def dodiff(ui, repo, cmdline, pats, opts):
132 132 '''Do the actual diff:
133 133
134 134 - copy to a temp structure if diffing 2 internal revisions
135 135 - copy to a temp structure if diffing working revision with
136 136 another one and more than 1 file is changed
137 137 - just invoke the diff for a single file in the working dir
138 138 '''
139 139
140 140 revs = opts.get('rev')
141 141 change = opts.get('change')
142 142 do3way = '$parent2' in cmdline
143 143
144 144 if revs and change:
145 145 msg = _('cannot specify --rev and --change at the same time')
146 146 raise error.Abort(msg)
147 147 elif change:
148 148 node2 = scmutil.revsingle(repo, change, None).node()
149 149 node1a, node1b = repo.changelog.parents(node2)
150 150 else:
151 151 node1a, node2 = scmutil.revpair(repo, revs)
152 152 if not revs:
153 153 node1b = repo.dirstate.p2()
154 154 else:
155 155 node1b = nullid
156 156
157 157 # Disable 3-way merge if there is only one parent
158 158 if do3way:
159 159 if node1b == nullid:
160 160 do3way = False
161 161
162 162 subrepos=opts.get('subrepos')
163 163
164 164 matcher = scmutil.match(repo[node2], pats, opts)
165 165
166 166 if opts.get('patch'):
167 167 if subrepos:
168 168 raise error.Abort(_('--patch cannot be used with --subrepos'))
169 169 if node2 is None:
170 170 raise error.Abort(_('--patch requires two revisions'))
171 171 else:
172 172 mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher,
173 173 listsubrepos=subrepos)[:3])
174 174 if do3way:
175 175 mod_b, add_b, rem_b = map(set,
176 176 repo.status(node1b, node2, matcher,
177 177 listsubrepos=subrepos)[:3])
178 178 else:
179 179 mod_b, add_b, rem_b = set(), set(), set()
180 180 modadd = mod_a | add_a | mod_b | add_b
181 181 common = modadd | rem_a | rem_b
182 182 if not common:
183 183 return 0
184 184
185 185 tmproot = tempfile.mkdtemp(prefix='extdiff.')
186 186 try:
187 187 if not opts.get('patch'):
188 188 # Always make a copy of node1a (and node1b, if applicable)
189 189 dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
190 190 dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot,
191 191 subrepos)[0]
192 192 rev1a = '@%d' % repo[node1a].rev()
193 193 if do3way:
194 194 dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
195 195 dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot,
196 196 subrepos)[0]
197 197 rev1b = '@%d' % repo[node1b].rev()
198 198 else:
199 199 dir1b = None
200 200 rev1b = ''
201 201
202 202 fns_and_mtime = []
203 203
204 204 # If node2 in not the wc or there is >1 change, copy it
205 205 dir2root = ''
206 206 rev2 = ''
207 207 if node2:
208 208 dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0]
209 209 rev2 = '@%d' % repo[node2].rev()
210 210 elif len(common) > 1:
211 211 #we only actually need to get the files to copy back to
212 212 #the working dir in this case (because the other cases
213 213 #are: diffing 2 revisions or single file -- in which case
214 214 #the file is already directly passed to the diff tool).
215 215 dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot,
216 216 subrepos)
217 217 else:
218 218 # This lets the diff tool open the changed file directly
219 219 dir2 = ''
220 220 dir2root = repo.root
221 221
222 222 label1a = rev1a
223 223 label1b = rev1b
224 224 label2 = rev2
225 225
226 226 # If only one change, diff the files instead of the directories
227 227 # Handle bogus modifies correctly by checking if the files exist
228 228 if len(common) == 1:
229 229 common_file = util.localpath(common.pop())
230 230 dir1a = os.path.join(tmproot, dir1a, common_file)
231 231 label1a = common_file + rev1a
232 232 if not os.path.isfile(dir1a):
233 233 dir1a = os.devnull
234 234 if do3way:
235 235 dir1b = os.path.join(tmproot, dir1b, common_file)
236 236 label1b = common_file + rev1b
237 237 if not os.path.isfile(dir1b):
238 238 dir1b = os.devnull
239 239 dir2 = os.path.join(dir2root, dir2, common_file)
240 240 label2 = common_file + rev2
241 241 else:
242 242 template = 'hg-%h.patch'
243 243 cmdutil.export(repo, [repo[node1a].rev(), repo[node2].rev()],
244 244 template=repo.vfs.reljoin(tmproot, template),
245 245 match=matcher)
246 246 label1a = cmdutil.makefilename(repo, template, node1a)
247 247 label2 = cmdutil.makefilename(repo, template, node2)
248 248 dir1a = repo.vfs.reljoin(tmproot, label1a)
249 249 dir2 = repo.vfs.reljoin(tmproot, label2)
250 250 dir1b = None
251 251 label1b = None
252 252 fns_and_mtime = []
253 253
254 254 # Function to quote file/dir names in the argument string.
255 255 # When not operating in 3-way mode, an empty string is
256 256 # returned for parent2
257 257 replace = {'parent': dir1a, 'parent1': dir1a, 'parent2': dir1b,
258 258 'plabel1': label1a, 'plabel2': label1b,
259 259 'clabel': label2, 'child': dir2,
260 260 'root': repo.root}
261 261 def quote(match):
262 262 pre = match.group(2)
263 263 key = match.group(3)
264 264 if not do3way and key == 'parent2':
265 265 return pre
266 266 return pre + util.shellquote(replace[key])
267 267
268 268 # Match parent2 first, so 'parent1?' will match both parent1 and parent
269 269 regex = (r'''(['"]?)([^\s'"$]*)'''
270 270 r'\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)\1')
271 271 if not do3way and not re.search(regex, cmdline):
272 272 cmdline += ' $parent1 $child'
273 273 cmdline = re.sub(regex, quote, cmdline)
274 274
275 275 ui.debug('running %r in %s\n' % (cmdline, tmproot))
276 276 ui.system(cmdline, cwd=tmproot)
277 277
278 278 for copy_fn, working_fn, mtime in fns_and_mtime:
279 279 if os.lstat(copy_fn).st_mtime != mtime:
280 280 ui.debug('file changed while diffing. '
281 281 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
282 282 util.copyfile(copy_fn, working_fn)
283 283
284 284 return 1
285 285 finally:
286 286 ui.note(_('cleaning up temp directory\n'))
287 287 shutil.rmtree(tmproot)
288 288
289 289 extdiffopts = [
290 290 ('o', 'option', [],
291 291 _('pass option to comparison program'), _('OPT')),
292 292 ('r', 'rev', [], _('revision'), _('REV')),
293 293 ('c', 'change', '', _('change made by revision'), _('REV')),
294 294 ('', 'patch', None, _('compare patches for two revisions'))
295 295 ] + commands.walkopts + commands.subrepoopts
296 296
297 297 @command('extdiff',
298 298 [('p', 'program', '', _('comparison program to run'), _('CMD')),
299 299 ] + extdiffopts,
300 300 _('hg extdiff [OPT]... [FILE]...'),
301 301 inferrepo=True)
302 302 def extdiff(ui, repo, *pats, **opts):
303 303 '''use external program to diff repository (or selected files)
304 304
305 305 Show differences between revisions for the specified files, using
306 306 an external program. The default program used is diff, with
307 307 default options "-Npru".
308 308
309 309 To select a different program, use the -p/--program option. The
310 310 program will be passed the names of two directories to compare. To
311 311 pass additional options to the program, use -o/--option. These
312 312 will be passed before the names of the directories to compare.
313 313
314 314 When two revision arguments are given, then changes are shown
315 315 between those revisions. If only one revision is specified then
316 316 that revision is compared to the working directory, and, when no
317 317 revisions are specified, the working directory files are compared
318 318 to its parent.'''
319 319 program = opts.get('program')
320 320 option = opts.get('option')
321 321 if not program:
322 322 program = 'diff'
323 323 option = option or ['-Npru']
324 324 cmdline = ' '.join(map(util.shellquote, [program] + option))
325 325 return dodiff(ui, repo, cmdline, pats, opts)
326 326
327 327 class savedcmd(object):
328 """use %(path)s to diff repository (or selected files)
328 """use external program to diff repository (or selected files)
329 329
330 330 Show differences between revisions for the specified files, using
331 the %(path)s program.
331 the following program::
332
333 %(path)s
332 334
333 335 When two revision arguments are given, then changes are shown
334 336 between those revisions. If only one revision is specified then
335 337 that revision is compared to the working directory, and, when no
336 338 revisions are specified, the working directory files are compared
337 339 to its parent.
338 340 """
339 341
340 342 def __init__(self, path, cmdline):
341 343 # We can't pass non-ASCII through docstrings (and path is
342 344 # in an unknown encoding anyway)
343 345 docpath = path.encode("string-escape")
344 346 self.__doc__ = self.__doc__ % {'path': util.uirepr(docpath)}
345 347 self._cmdline = cmdline
346 348
347 349 def __call__(self, ui, repo, *pats, **opts):
348 350 options = ' '.join(map(util.shellquote, opts['option']))
349 351 if options:
350 352 options = ' ' + options
351 353 return dodiff(ui, repo, self._cmdline + options, pats, opts)
352 354
353 355 def uisetup(ui):
354 356 for cmd, path in ui.configitems('extdiff'):
355 357 path = util.expandpath(path)
356 358 if cmd.startswith('cmd.'):
357 359 cmd = cmd[4:]
358 360 if not path:
359 361 path = util.findexe(cmd)
360 362 if path is None:
361 363 path = filemerge.findexternaltool(ui, cmd) or cmd
362 364 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
363 365 cmdline = util.shellquote(path)
364 366 if diffopts:
365 367 cmdline += ' ' + diffopts
366 368 elif cmd.startswith('opts.'):
367 369 continue
368 370 else:
369 371 if path:
370 372 # case "cmd = path opts"
371 373 cmdline = path
372 374 diffopts = len(shlex.split(cmdline)) > 1
373 375 else:
374 376 # case "cmd ="
375 377 path = util.findexe(cmd)
376 378 if path is None:
377 379 path = filemerge.findexternaltool(ui, cmd) or cmd
378 380 cmdline = util.shellquote(path)
379 381 diffopts = False
380 382 # look for diff arguments in [diff-tools] then [merge-tools]
381 383 if not diffopts:
382 384 args = ui.config('diff-tools', cmd+'.diffargs') or \
383 385 ui.config('merge-tools', cmd+'.diffargs')
384 386 if args:
385 387 cmdline += ' ' + args
386 388 command(cmd, extdiffopts[:], _('hg %s [OPTION]... [FILE]...') % cmd,
387 389 inferrepo=True)(savedcmd(path, cmdline))
388 390
389 391 # tell hggettext to extract docstrings from these functions:
390 392 i18nfunctions = [savedcmd]
@@ -1,411 +1,414 b''
1 1 $ echo "[extensions]" >> $HGRCPATH
2 2 $ echo "extdiff=" >> $HGRCPATH
3 3
4 4 $ hg init a
5 5 $ cd a
6 6 $ echo a > a
7 7 $ echo b > b
8 8 $ hg add
9 9 adding a
10 10 adding b
11 11
12 12 Should diff cloned directories:
13 13
14 14 $ hg extdiff -o -r $opt
15 15 Only in a: a
16 16 Only in a: b
17 17 [1]
18 18
19 19 $ cat <<EOF >> $HGRCPATH
20 20 > [extdiff]
21 21 > cmd.falabala = echo
22 22 > opts.falabala = diffing
23 23 > cmd.edspace = echo
24 24 > opts.edspace = "name <user@example.com>"
25 25 > EOF
26 26
27 27 $ hg falabala
28 28 diffing a.000000000000 a
29 29 [1]
30 30
31 31 $ hg help falabala
32 32 hg falabala [OPTION]... [FILE]...
33 33
34 use 'echo' to diff repository (or selected files)
34 use external program to diff repository (or selected files)
35 35
36 36 Show differences between revisions for the specified files, using the
37 'echo' program.
37 following program:
38
39 'echo'
38 40
39 41 When two revision arguments are given, then changes are shown between
40 42 those revisions. If only one revision is specified then that revision is
41 43 compared to the working directory, and, when no revisions are specified,
42 44 the working directory files are compared to its parent.
43 45
44 46 options ([+] can be repeated):
45 47
46 48 -o --option OPT [+] pass option to comparison program
47 49 -r --rev REV [+] revision
48 50 -c --change REV change made by revision
49 51 --patch compare patches for two revisions
50 52 -I --include PATTERN [+] include names matching the given patterns
51 53 -X --exclude PATTERN [+] exclude names matching the given patterns
52 54 -S --subrepos recurse into subrepositories
53 55
54 56 (some details hidden, use --verbose to show complete help)
55 57
56 58 $ hg ci -d '0 0' -mtest1
57 59
58 60 $ echo b >> a
59 61 $ hg ci -d '1 0' -mtest2
60 62
61 63 Should diff cloned files directly:
62 64
63 65 #if windows
64 66 $ hg falabala -r 0:1
65 67 diffing "*\\extdiff.*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob)
66 68 [1]
67 69 #else
68 70 $ hg falabala -r 0:1
69 71 diffing */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
70 72 [1]
71 73 #endif
72 74
73 75 Specifying an empty revision should abort.
74 76
75 77 $ hg extdiff -p diff --patch --rev 'ancestor()' --rev 1
76 78 abort: empty revision on one side of range
77 79 [255]
78 80
79 81 Test diff during merge:
80 82
81 83 $ hg update -C 0
82 84 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 85 $ echo c >> c
84 86 $ hg add c
85 87 $ hg ci -m "new branch" -d '1 0'
86 88 created new head
87 89 $ hg merge 1
88 90 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 91 (branch merge, don't forget to commit)
90 92
91 93 Should diff cloned file against wc file:
92 94
93 95 #if windows
94 96 $ hg falabala
95 97 diffing "*\\extdiff.*\\a.2a13a4d2da36\\a" "*\\a\\a" (glob)
96 98 [1]
97 99 #else
98 100 $ hg falabala
99 101 diffing */extdiff.*/a.2a13a4d2da36/a */a/a (glob)
100 102 [1]
101 103 #endif
102 104
103 105
104 106 Test --change option:
105 107
106 108 $ hg ci -d '2 0' -mtest3
107 109 #if windows
108 110 $ hg falabala -c 1
109 111 diffing "*\\extdiff.*\\a.8a5febb7f867\\a" "a.34eed99112ab\\a" (glob)
110 112 [1]
111 113 #else
112 114 $ hg falabala -c 1
113 115 diffing */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
114 116 [1]
115 117 #endif
116 118
117 119 Check diff are made from the first parent:
118 120
119 121 #if windows
120 122 $ hg falabala -c 3 || echo "diff-like tools yield a non-zero exit code"
121 123 diffing "*\\extdiff.*\\a.2a13a4d2da36\\a" "a.46c0e4daeb72\\a" (glob)
122 124 diff-like tools yield a non-zero exit code
123 125 #else
124 126 $ hg falabala -c 3 || echo "diff-like tools yield a non-zero exit code"
125 127 diffing */extdiff.*/a.2a13a4d2da36/a a.46c0e4daeb72/a (glob)
126 128 diff-like tools yield a non-zero exit code
127 129 #endif
128 130
129 131 issue3153: ensure using extdiff with removed subrepos doesn't crash:
130 132
131 133 $ hg init suba
132 134 $ cd suba
133 135 $ echo suba > suba
134 136 $ hg add
135 137 adding suba
136 138 $ hg ci -m "adding suba file"
137 139 $ cd ..
138 140 $ echo suba=suba > .hgsub
139 141 $ hg add
140 142 adding .hgsub
141 143 $ hg ci -Sm "adding subrepo"
142 144 $ echo > .hgsub
143 145 $ hg ci -m "removing subrepo"
144 146 $ hg falabala -r 4 -r 5 -S
145 147 diffing a.398e36faf9c6 a.5ab95fb166c4
146 148 [1]
147 149
148 150 issue4463: usage of command line configuration without additional quoting
149 151
150 152 $ cat <<EOF >> $HGRCPATH
151 153 > [extdiff]
152 154 > cmd.4463a = echo
153 155 > opts.4463a = a-naked 'single quoted' "double quoted"
154 156 > 4463b = echo b-naked 'single quoted' "double quoted"
155 157 > echo =
156 158 > EOF
157 159 $ hg update -q -C 0
158 160 $ echo a >> a
159 161 #if windows
160 162 $ hg --debug 4463a | grep '^running'
161 163 running 'echo a-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
162 164 $ hg --debug 4463b | grep '^running'
163 165 running 'echo b-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
164 166 $ hg --debug echo | grep '^running'
165 167 running '*echo* "*\\a" "*\\a"' in */extdiff.* (glob)
166 168 #else
167 169 $ hg --debug 4463a | grep '^running'
168 170 running 'echo a-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob)
169 171 $ hg --debug 4463b | grep '^running'
170 172 running 'echo b-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob)
171 173 $ hg --debug echo | grep '^running'
172 174 running '*echo */a $TESTTMP/a/a' in */extdiff.* (glob)
173 175 #endif
174 176
175 177 (getting options from other than extdiff section)
176 178
177 179 $ cat <<EOF >> $HGRCPATH
178 180 > [extdiff]
179 181 > # using diff-tools diffargs
180 182 > 4463b2 = echo
181 183 > # using merge-tools diffargs
182 184 > 4463b3 = echo
183 185 > # no diffargs
184 186 > 4463b4 = echo
185 187 > [diff-tools]
186 188 > 4463b2.diffargs = b2-naked 'single quoted' "double quoted"
187 189 > [merge-tools]
188 190 > 4463b3.diffargs = b3-naked 'single quoted' "double quoted"
189 191 > EOF
190 192 #if windows
191 193 $ hg --debug 4463b2 | grep '^running'
192 194 running 'echo b2-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
193 195 $ hg --debug 4463b3 | grep '^running'
194 196 running 'echo b3-naked \'single quoted\' "double quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
195 197 $ hg --debug 4463b4 | grep '^running'
196 198 running 'echo "*\\a" "*\\a"' in */extdiff.* (glob)
197 199 $ hg --debug 4463b4 --option b4-naked --option 'being quoted' | grep '^running'
198 200 running 'echo b4-naked "being quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
199 201 $ hg --debug extdiff -p echo --option echo-naked --option 'being quoted' | grep '^running'
200 202 running 'echo echo-naked "being quoted" "*\\a" "*\\a"' in */extdiff.* (glob)
201 203 #else
202 204 $ hg --debug 4463b2 | grep '^running'
203 205 running 'echo b2-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob)
204 206 $ hg --debug 4463b3 | grep '^running'
205 207 running 'echo b3-naked \'single quoted\' "double quoted" */a $TESTTMP/a/a' in */extdiff.* (glob)
206 208 $ hg --debug 4463b4 | grep '^running'
207 209 running 'echo */a $TESTTMP/a/a' in */extdiff.* (glob)
208 210 $ hg --debug 4463b4 --option b4-naked --option 'being quoted' | grep '^running'
209 211 running "echo b4-naked 'being quoted' */a $TESTTMP/a/a" in */extdiff.* (glob)
210 212 $ hg --debug extdiff -p echo --option echo-naked --option 'being quoted' | grep '^running'
211 213 running "echo echo-naked 'being quoted' */a $TESTTMP/a/a" in */extdiff.* (glob)
212 214 #endif
213 215
214 216 $ touch 'sp ace'
215 217 $ hg add 'sp ace'
216 218 $ hg ci -m 'sp ace'
217 219 created new head
218 220 $ echo > 'sp ace'
219 221
220 222 Test pre-72a89cf86fcd backward compatibility with half-baked manual quoting
221 223
222 224 $ cat <<EOF >> $HGRCPATH
223 225 > [extdiff]
224 226 > odd =
225 227 > [merge-tools]
226 228 > odd.diffargs = --foo='\$clabel' '\$clabel' "--bar=\$clabel" "\$clabel"
227 229 > odd.executable = echo
228 230 > EOF
229 231 #if windows
230 232 TODO
231 233 #else
232 234 $ hg --debug odd | grep '^running'
233 235 running "*/echo --foo='sp ace' 'sp ace' --bar='sp ace' 'sp ace'" in * (glob)
234 236 #endif
235 237
236 238 Empty argument must be quoted
237 239
238 240 $ cat <<EOF >> $HGRCPATH
239 241 > [extdiff]
240 242 > kdiff3 = echo
241 243 > [merge-tools]
242 244 > kdiff3.diffargs=--L1 \$plabel1 --L2 \$clabel \$parent \$child
243 245 > EOF
244 246 #if windows
245 247 $ hg --debug kdiff3 -r0 | grep '^running'
246 248 running 'echo --L1 "@0" --L2 "" a.8a5febb7f867 a' in * (glob)
247 249 #else
248 250 $ hg --debug kdiff3 -r0 | grep '^running'
249 251 running "echo --L1 '@0' --L2 '' a.8a5febb7f867 a" in * (glob)
250 252 #endif
251 253
252 254 #if execbit
253 255
254 256 Test extdiff of multiple files in tmp dir:
255 257
256 258 $ hg update -C 0 > /dev/null
257 259 $ echo changed > a
258 260 $ echo changed > b
259 261 $ chmod +x b
260 262
261 263 Diff in working directory, before:
262 264
263 265 $ hg diff --git
264 266 diff --git a/a b/a
265 267 --- a/a
266 268 +++ b/a
267 269 @@ -1,1 +1,1 @@
268 270 -a
269 271 +changed
270 272 diff --git a/b b/b
271 273 old mode 100644
272 274 new mode 100755
273 275 --- a/b
274 276 +++ b/b
275 277 @@ -1,1 +1,1 @@
276 278 -b
277 279 +changed
278 280
279 281
280 282 Edit with extdiff -p:
281 283
282 284 Prepare custom diff/edit tool:
283 285
284 286 $ cat > 'diff tool.py' << EOT
285 287 > #!/usr/bin/env python
286 288 > import time
287 289 > time.sleep(1) # avoid unchanged-timestamp problems
288 290 > file('a/a', 'ab').write('edited\n')
289 291 > file('a/b', 'ab').write('edited\n')
290 292 > EOT
291 293
292 294 $ chmod +x 'diff tool.py'
293 295
294 296 will change to /tmp/extdiff.TMP and populate directories a.TMP and a
295 297 and start tool
296 298
297 299 $ hg extdiff -p "`pwd`/diff tool.py"
298 300 [1]
299 301
300 302 Diff in working directory, after:
301 303
302 304 $ hg diff --git
303 305 diff --git a/a b/a
304 306 --- a/a
305 307 +++ b/a
306 308 @@ -1,1 +1,2 @@
307 309 -a
308 310 +changed
309 311 +edited
310 312 diff --git a/b b/b
311 313 old mode 100644
312 314 new mode 100755
313 315 --- a/b
314 316 +++ b/b
315 317 @@ -1,1 +1,2 @@
316 318 -b
317 319 +changed
318 320 +edited
319 321
320 322 Test extdiff with --option:
321 323
322 324 $ hg extdiff -p echo -o this -c 1
323 325 this */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
324 326 [1]
325 327
326 328 $ hg falabala -o this -c 1
327 329 diffing this */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
328 330 [1]
329 331
330 332 Test extdiff's handling of options with spaces in them:
331 333
332 334 $ hg edspace -c 1
333 335 name <user@example.com> */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
334 336 [1]
335 337
336 338 $ hg extdiff -p echo -o "name <user@example.com>" -c 1
337 339 name <user@example.com> */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
338 340 [1]
339 341
340 342 Test with revsets:
341 343
342 344 $ hg extdif -p echo -c "rev(1)"
343 345 */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
344 346 [1]
345 347
346 348 $ hg extdif -p echo -r "0::1"
347 349 */extdiff.*/a.8a5febb7f867/a a.34eed99112ab/a (glob)
348 350 [1]
349 351
350 352 Fallback to merge-tools.tool.executable|regkey
351 353 $ mkdir dir
352 354 $ cat > 'dir/tool.sh' << EOF
353 355 > #!/bin/sh
354 356 > echo "** custom diff **"
355 357 > EOF
356 358 $ chmod +x dir/tool.sh
357 359 $ tool=`pwd`/dir/tool.sh
358 360 $ hg --debug tl --config extdiff.tl= --config merge-tools.tl.executable=$tool
359 361 making snapshot of 2 files from rev * (glob)
360 362 a
361 363 b
362 364 making snapshot of 2 files from working directory
363 365 a
364 366 b
365 367 running '$TESTTMP/a/dir/tool.sh a.* a' in */extdiff.* (glob)
366 368 ** custom diff **
367 369 cleaning up temp directory
368 370 [1]
369 371
370 372 $ cd ..
371 373
372 374 #endif
373 375
374 376 #if symlink
375 377
376 378 Test symlinks handling (issue1909)
377 379
378 380 $ hg init testsymlinks
379 381 $ cd testsymlinks
380 382 $ echo a > a
381 383 $ hg ci -Am adda
382 384 adding a
383 385 $ echo a >> a
384 386 $ ln -s missing linka
385 387 $ hg add linka
386 388 $ hg falabala -r 0 --traceback
387 389 diffing testsymlinks.07f494440405 testsymlinks
388 390 [1]
389 391 $ cd ..
390 392
391 393 #endif
392 394
393 395 Test handling of non-ASCII paths in generated docstrings (issue5301)
394 396
395 397 >>> open("u", "w").write("\xa5\xa5")
396 398 $ U=`cat u`
397 399
398 400 $ HGPLAIN=1 hg --config hgext.extdiff= --config extdiff.cmd.td=hi help -k xyzzy
399 401 abort: no matches
400 402 (try "hg help" for a list of topics)
401 403 [255]
402 404
403 405 $ HGPLAIN=1 hg --config hgext.extdiff= --config extdiff.cmd.td=hi help td > /dev/null
404 406
405 407 $ LC_MESSAGES=ja_JP.UTF-8 hg --config hgext.extdiff= --config extdiff.cmd.td=$U help -k xyzzy
406 408 abort: no matches
407 409 (try "hg help" for a list of topics)
408 410 [255]
409 411
410 $ LC_MESSAGES=ja_JP.UTF-8 hg --config hgext.extdiff= --config extdiff.cmd.td=$U help td | grep "^use"
411 use '\xa5\xa5' to diff repository (or selected files)
412 $ LC_MESSAGES=ja_JP.UTF-8 hg --config hgext.extdiff= --config extdiff.cmd.td=$U help td \
413 > | grep "^ '"
414 '\xa5\xa5'
General Comments 0
You need to be logged in to leave comments. Login now