##// END OF EJS Templates
extdiff: allow modifications in subrepos to be copied back...
Matt Harbison -
r25876:415709a4 stable
parent child Browse files
Show More
@@ -1,353 +1,349
1 # extdiff.py - external diff program support for mercurial
1 # extdiff.py - external diff program support for mercurial
2 #
2 #
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 '''command to allow external programs to compare revisions
8 '''command to allow external programs to compare revisions
9
9
10 The extdiff Mercurial extension allows you to use external programs
10 The extdiff Mercurial extension allows you to use external programs
11 to compare revisions, or revision with working directory. The external
11 to compare revisions, or revision with working directory. The external
12 diff programs are called with a configurable set of options and two
12 diff programs are called with a configurable set of options and two
13 non-option arguments: paths to directories containing snapshots of
13 non-option arguments: paths to directories containing snapshots of
14 files to compare.
14 files to compare.
15
15
16 The extdiff extension also allows you to configure new diff commands, so
16 The extdiff extension also allows you to configure new diff commands, so
17 you do not need to type :hg:`extdiff -p kdiff3` always. ::
17 you do not need to type :hg:`extdiff -p kdiff3` always. ::
18
18
19 [extdiff]
19 [extdiff]
20 # add new command that runs GNU diff(1) in 'context diff' mode
20 # add new command that runs GNU diff(1) in 'context diff' mode
21 cdiff = gdiff -Nprc5
21 cdiff = gdiff -Nprc5
22 ## or the old way:
22 ## or the old way:
23 #cmd.cdiff = gdiff
23 #cmd.cdiff = gdiff
24 #opts.cdiff = -Nprc5
24 #opts.cdiff = -Nprc5
25
25
26 # add new command called meld, runs meld (no need to name twice). If
26 # add new command called meld, runs meld (no need to name twice). If
27 # the meld executable is not available, the meld tool in [merge-tools]
27 # the meld executable is not available, the meld tool in [merge-tools]
28 # will be used, if available
28 # will be used, if available
29 meld =
29 meld =
30
30
31 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
31 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
32 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
32 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
33 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
33 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
34 # your .vimrc
34 # your .vimrc
35 vimdiff = gvim -f "+next" \\
35 vimdiff = gvim -f "+next" \\
36 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
36 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
37
37
38 Tool arguments can include variables that are expanded at runtime::
38 Tool arguments can include variables that are expanded at runtime::
39
39
40 $parent1, $plabel1 - filename, descriptive label of first parent
40 $parent1, $plabel1 - filename, descriptive label of first parent
41 $child, $clabel - filename, descriptive label of child revision
41 $child, $clabel - filename, descriptive label of child revision
42 $parent2, $plabel2 - filename, descriptive label of second parent
42 $parent2, $plabel2 - filename, descriptive label of second parent
43 $root - repository root
43 $root - repository root
44 $parent is an alias for $parent1.
44 $parent is an alias for $parent1.
45
45
46 The extdiff extension will look in your [diff-tools] and [merge-tools]
46 The extdiff extension will look in your [diff-tools] and [merge-tools]
47 sections for diff tool arguments, when none are specified in [extdiff].
47 sections for diff tool arguments, when none are specified in [extdiff].
48
48
49 ::
49 ::
50
50
51 [extdiff]
51 [extdiff]
52 kdiff3 =
52 kdiff3 =
53
53
54 [diff-tools]
54 [diff-tools]
55 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
55 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
56
56
57 You can use -I/-X and list of file or directory names like normal
57 You can use -I/-X and list of file or directory names like normal
58 :hg:`diff` command. The extdiff extension makes snapshots of only
58 :hg:`diff` command. The extdiff extension makes snapshots of only
59 needed files, so running the external diff program will actually be
59 needed files, so running the external diff program will actually be
60 pretty fast (at least faster than having to compare the entire tree).
60 pretty fast (at least faster than having to compare the entire tree).
61 '''
61 '''
62
62
63 from mercurial.i18n import _
63 from mercurial.i18n import _
64 from mercurial.node import short, nullid
64 from mercurial.node import short, nullid
65 from mercurial import cmdutil, scmutil, util, commands, encoding, filemerge
65 from mercurial import cmdutil, scmutil, util, commands, encoding, filemerge
66 from mercurial import archival
66 from mercurial import archival
67 import os, shlex, shutil, tempfile, re
67 import os, shlex, shutil, tempfile, re
68
68
69 cmdtable = {}
69 cmdtable = {}
70 command = cmdutil.command(cmdtable)
70 command = cmdutil.command(cmdtable)
71 # Note for extension authors: ONLY specify testedwith = 'internal' for
71 # Note for extension authors: ONLY specify testedwith = 'internal' for
72 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
72 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
73 # be specifying the version(s) of Mercurial they are tested with, or
73 # be specifying the version(s) of Mercurial they are tested with, or
74 # leave the attribute unspecified.
74 # leave the attribute unspecified.
75 testedwith = 'internal'
75 testedwith = 'internal'
76
76
77 def snapshot(ui, repo, files, node, tmproot, listsubrepos):
77 def snapshot(ui, repo, files, node, tmproot, listsubrepos):
78 '''snapshot files as of some revision
78 '''snapshot files as of some revision
79 if not using snapshot, -I/-X does not work and recursive diff
79 if not using snapshot, -I/-X does not work and recursive diff
80 in tools like kdiff3 and meld displays too many files.'''
80 in tools like kdiff3 and meld displays too many files.'''
81 dirname = os.path.basename(repo.root)
81 dirname = os.path.basename(repo.root)
82 if dirname == "":
82 if dirname == "":
83 dirname = "root"
83 dirname = "root"
84 if node is not None:
84 if node is not None:
85 dirname = '%s.%s' % (dirname, short(node))
85 dirname = '%s.%s' % (dirname, short(node))
86 base = os.path.join(tmproot, dirname)
86 base = os.path.join(tmproot, dirname)
87 os.mkdir(base)
87 os.mkdir(base)
88 fns_and_mtime = []
88 fns_and_mtime = []
89
89
90 if node is not None:
90 if node is not None:
91 ui.note(_('making snapshot of %d files from rev %s\n') %
91 ui.note(_('making snapshot of %d files from rev %s\n') %
92 (len(files), short(node)))
92 (len(files), short(node)))
93 else:
93 else:
94 ui.note(_('making snapshot of %d files from working directory\n') %
94 ui.note(_('making snapshot of %d files from working directory\n') %
95 (len(files)))
95 (len(files)))
96
96
97 if files:
97 if files:
98 repo.ui.setconfig("ui", "archivemeta", False)
98 repo.ui.setconfig("ui", "archivemeta", False)
99
99
100 archival.archive(repo, base, node, 'files',
100 archival.archive(repo, base, node, 'files',
101 matchfn=scmutil.matchfiles(repo, files),
101 matchfn=scmutil.matchfiles(repo, files),
102 subrepos=listsubrepos)
102 subrepos=listsubrepos)
103
103
104 ctx = repo[node]
105 for fn in sorted(files):
104 for fn in sorted(files):
106 wfn = util.pconvert(fn)
105 wfn = util.pconvert(fn)
107 if wfn not in ctx:
108 # File doesn't exist; could be a bogus modify
109 continue
110 ui.note(' %s\n' % wfn)
106 ui.note(' %s\n' % wfn)
111
107
112 if node is None:
108 if node is None:
113 dest = os.path.join(base, wfn)
109 dest = os.path.join(base, wfn)
114
110
115 fns_and_mtime.append((dest, repo.wjoin(fn),
111 fns_and_mtime.append((dest, repo.wjoin(fn),
116 os.lstat(dest).st_mtime))
112 os.lstat(dest).st_mtime))
117 return dirname, fns_and_mtime
113 return dirname, fns_and_mtime
118
114
119 def dodiff(ui, repo, cmdline, pats, opts):
115 def dodiff(ui, repo, cmdline, pats, opts):
120 '''Do the actual diff:
116 '''Do the actual diff:
121
117
122 - copy to a temp structure if diffing 2 internal revisions
118 - copy to a temp structure if diffing 2 internal revisions
123 - copy to a temp structure if diffing working revision with
119 - copy to a temp structure if diffing working revision with
124 another one and more than 1 file is changed
120 another one and more than 1 file is changed
125 - just invoke the diff for a single file in the working dir
121 - just invoke the diff for a single file in the working dir
126 '''
122 '''
127
123
128 revs = opts.get('rev')
124 revs = opts.get('rev')
129 change = opts.get('change')
125 change = opts.get('change')
130 do3way = '$parent2' in cmdline
126 do3way = '$parent2' in cmdline
131
127
132 if revs and change:
128 if revs and change:
133 msg = _('cannot specify --rev and --change at the same time')
129 msg = _('cannot specify --rev and --change at the same time')
134 raise util.Abort(msg)
130 raise util.Abort(msg)
135 elif change:
131 elif change:
136 node2 = scmutil.revsingle(repo, change, None).node()
132 node2 = scmutil.revsingle(repo, change, None).node()
137 node1a, node1b = repo.changelog.parents(node2)
133 node1a, node1b = repo.changelog.parents(node2)
138 else:
134 else:
139 node1a, node2 = scmutil.revpair(repo, revs)
135 node1a, node2 = scmutil.revpair(repo, revs)
140 if not revs:
136 if not revs:
141 node1b = repo.dirstate.p2()
137 node1b = repo.dirstate.p2()
142 else:
138 else:
143 node1b = nullid
139 node1b = nullid
144
140
145 # Disable 3-way merge if there is only one parent
141 # Disable 3-way merge if there is only one parent
146 if do3way:
142 if do3way:
147 if node1b == nullid:
143 if node1b == nullid:
148 do3way = False
144 do3way = False
149
145
150 subrepos=opts.get('subrepos')
146 subrepos=opts.get('subrepos')
151
147
152 matcher = scmutil.match(repo[node2], pats, opts)
148 matcher = scmutil.match(repo[node2], pats, opts)
153 mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher,
149 mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher,
154 listsubrepos=subrepos)[:3])
150 listsubrepos=subrepos)[:3])
155 if do3way:
151 if do3way:
156 mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher,
152 mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher,
157 listsubrepos=subrepos)[:3])
153 listsubrepos=subrepos)[:3])
158 else:
154 else:
159 mod_b, add_b, rem_b = set(), set(), set()
155 mod_b, add_b, rem_b = set(), set(), set()
160 modadd = mod_a | add_a | mod_b | add_b
156 modadd = mod_a | add_a | mod_b | add_b
161 common = modadd | rem_a | rem_b
157 common = modadd | rem_a | rem_b
162 if not common:
158 if not common:
163 return 0
159 return 0
164
160
165 tmproot = tempfile.mkdtemp(prefix='extdiff.')
161 tmproot = tempfile.mkdtemp(prefix='extdiff.')
166 try:
162 try:
167 # Always make a copy of node1a (and node1b, if applicable)
163 # Always make a copy of node1a (and node1b, if applicable)
168 dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
164 dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
169 dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[0]
165 dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[0]
170 rev1a = '@%d' % repo[node1a].rev()
166 rev1a = '@%d' % repo[node1a].rev()
171 if do3way:
167 if do3way:
172 dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
168 dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
173 dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot,
169 dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot,
174 subrepos)[0]
170 subrepos)[0]
175 rev1b = '@%d' % repo[node1b].rev()
171 rev1b = '@%d' % repo[node1b].rev()
176 else:
172 else:
177 dir1b = None
173 dir1b = None
178 rev1b = ''
174 rev1b = ''
179
175
180 fns_and_mtime = []
176 fns_and_mtime = []
181
177
182 # If node2 in not the wc or there is >1 change, copy it
178 # If node2 in not the wc or there is >1 change, copy it
183 dir2root = ''
179 dir2root = ''
184 rev2 = ''
180 rev2 = ''
185 if node2:
181 if node2:
186 dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0]
182 dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0]
187 rev2 = '@%d' % repo[node2].rev()
183 rev2 = '@%d' % repo[node2].rev()
188 elif len(common) > 1:
184 elif len(common) > 1:
189 #we only actually need to get the files to copy back to
185 #we only actually need to get the files to copy back to
190 #the working dir in this case (because the other cases
186 #the working dir in this case (because the other cases
191 #are: diffing 2 revisions or single file -- in which case
187 #are: diffing 2 revisions or single file -- in which case
192 #the file is already directly passed to the diff tool).
188 #the file is already directly passed to the diff tool).
193 dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot,
189 dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot,
194 subrepos)
190 subrepos)
195 else:
191 else:
196 # This lets the diff tool open the changed file directly
192 # This lets the diff tool open the changed file directly
197 dir2 = ''
193 dir2 = ''
198 dir2root = repo.root
194 dir2root = repo.root
199
195
200 label1a = rev1a
196 label1a = rev1a
201 label1b = rev1b
197 label1b = rev1b
202 label2 = rev2
198 label2 = rev2
203
199
204 # If only one change, diff the files instead of the directories
200 # If only one change, diff the files instead of the directories
205 # Handle bogus modifies correctly by checking if the files exist
201 # Handle bogus modifies correctly by checking if the files exist
206 if len(common) == 1:
202 if len(common) == 1:
207 common_file = util.localpath(common.pop())
203 common_file = util.localpath(common.pop())
208 dir1a = os.path.join(tmproot, dir1a, common_file)
204 dir1a = os.path.join(tmproot, dir1a, common_file)
209 label1a = common_file + rev1a
205 label1a = common_file + rev1a
210 if not os.path.isfile(dir1a):
206 if not os.path.isfile(dir1a):
211 dir1a = os.devnull
207 dir1a = os.devnull
212 if do3way:
208 if do3way:
213 dir1b = os.path.join(tmproot, dir1b, common_file)
209 dir1b = os.path.join(tmproot, dir1b, common_file)
214 label1b = common_file + rev1b
210 label1b = common_file + rev1b
215 if not os.path.isfile(dir1b):
211 if not os.path.isfile(dir1b):
216 dir1b = os.devnull
212 dir1b = os.devnull
217 dir2 = os.path.join(dir2root, dir2, common_file)
213 dir2 = os.path.join(dir2root, dir2, common_file)
218 label2 = common_file + rev2
214 label2 = common_file + rev2
219
215
220 # Function to quote file/dir names in the argument string.
216 # Function to quote file/dir names in the argument string.
221 # When not operating in 3-way mode, an empty string is
217 # When not operating in 3-way mode, an empty string is
222 # returned for parent2
218 # returned for parent2
223 replace = {'parent': dir1a, 'parent1': dir1a, 'parent2': dir1b,
219 replace = {'parent': dir1a, 'parent1': dir1a, 'parent2': dir1b,
224 'plabel1': label1a, 'plabel2': label1b,
220 'plabel1': label1a, 'plabel2': label1b,
225 'clabel': label2, 'child': dir2,
221 'clabel': label2, 'child': dir2,
226 'root': repo.root}
222 'root': repo.root}
227 def quote(match):
223 def quote(match):
228 pre = match.group(2)
224 pre = match.group(2)
229 key = match.group(3)
225 key = match.group(3)
230 if not do3way and key == 'parent2':
226 if not do3way and key == 'parent2':
231 return pre
227 return pre
232 return pre + util.shellquote(replace[key])
228 return pre + util.shellquote(replace[key])
233
229
234 # Match parent2 first, so 'parent1?' will match both parent1 and parent
230 # Match parent2 first, so 'parent1?' will match both parent1 and parent
235 regex = (r'''(['"]?)([^\s'"$]*)'''
231 regex = (r'''(['"]?)([^\s'"$]*)'''
236 r'\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)\1')
232 r'\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)\1')
237 if not do3way and not re.search(regex, cmdline):
233 if not do3way and not re.search(regex, cmdline):
238 cmdline += ' $parent1 $child'
234 cmdline += ' $parent1 $child'
239 cmdline = re.sub(regex, quote, cmdline)
235 cmdline = re.sub(regex, quote, cmdline)
240
236
241 ui.debug('running %r in %s\n' % (cmdline, tmproot))
237 ui.debug('running %r in %s\n' % (cmdline, tmproot))
242 ui.system(cmdline, cwd=tmproot)
238 ui.system(cmdline, cwd=tmproot)
243
239
244 for copy_fn, working_fn, mtime in fns_and_mtime:
240 for copy_fn, working_fn, mtime in fns_and_mtime:
245 if os.lstat(copy_fn).st_mtime != mtime:
241 if os.lstat(copy_fn).st_mtime != mtime:
246 ui.debug('file changed while diffing. '
242 ui.debug('file changed while diffing. '
247 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
243 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
248 util.copyfile(copy_fn, working_fn)
244 util.copyfile(copy_fn, working_fn)
249
245
250 return 1
246 return 1
251 finally:
247 finally:
252 ui.note(_('cleaning up temp directory\n'))
248 ui.note(_('cleaning up temp directory\n'))
253 shutil.rmtree(tmproot)
249 shutil.rmtree(tmproot)
254
250
255 @command('extdiff',
251 @command('extdiff',
256 [('p', 'program', '',
252 [('p', 'program', '',
257 _('comparison program to run'), _('CMD')),
253 _('comparison program to run'), _('CMD')),
258 ('o', 'option', [],
254 ('o', 'option', [],
259 _('pass option to comparison program'), _('OPT')),
255 _('pass option to comparison program'), _('OPT')),
260 ('r', 'rev', [], _('revision'), _('REV')),
256 ('r', 'rev', [], _('revision'), _('REV')),
261 ('c', 'change', '', _('change made by revision'), _('REV')),
257 ('c', 'change', '', _('change made by revision'), _('REV')),
262 ] + commands.walkopts + commands.subrepoopts,
258 ] + commands.walkopts + commands.subrepoopts,
263 _('hg extdiff [OPT]... [FILE]...'),
259 _('hg extdiff [OPT]... [FILE]...'),
264 inferrepo=True)
260 inferrepo=True)
265 def extdiff(ui, repo, *pats, **opts):
261 def extdiff(ui, repo, *pats, **opts):
266 '''use external program to diff repository (or selected files)
262 '''use external program to diff repository (or selected files)
267
263
268 Show differences between revisions for the specified files, using
264 Show differences between revisions for the specified files, using
269 an external program. The default program used is diff, with
265 an external program. The default program used is diff, with
270 default options "-Npru".
266 default options "-Npru".
271
267
272 To select a different program, use the -p/--program option. The
268 To select a different program, use the -p/--program option. The
273 program will be passed the names of two directories to compare. To
269 program will be passed the names of two directories to compare. To
274 pass additional options to the program, use -o/--option. These
270 pass additional options to the program, use -o/--option. These
275 will be passed before the names of the directories to compare.
271 will be passed before the names of the directories to compare.
276
272
277 When two revision arguments are given, then changes are shown
273 When two revision arguments are given, then changes are shown
278 between those revisions. If only one revision is specified then
274 between those revisions. If only one revision is specified then
279 that revision is compared to the working directory, and, when no
275 that revision is compared to the working directory, and, when no
280 revisions are specified, the working directory files are compared
276 revisions are specified, the working directory files are compared
281 to its parent.'''
277 to its parent.'''
282 program = opts.get('program')
278 program = opts.get('program')
283 option = opts.get('option')
279 option = opts.get('option')
284 if not program:
280 if not program:
285 program = 'diff'
281 program = 'diff'
286 option = option or ['-Npru']
282 option = option or ['-Npru']
287 cmdline = ' '.join(map(util.shellquote, [program] + option))
283 cmdline = ' '.join(map(util.shellquote, [program] + option))
288 return dodiff(ui, repo, cmdline, pats, opts)
284 return dodiff(ui, repo, cmdline, pats, opts)
289
285
290 def uisetup(ui):
286 def uisetup(ui):
291 for cmd, path in ui.configitems('extdiff'):
287 for cmd, path in ui.configitems('extdiff'):
292 path = util.expandpath(path)
288 path = util.expandpath(path)
293 if cmd.startswith('cmd.'):
289 if cmd.startswith('cmd.'):
294 cmd = cmd[4:]
290 cmd = cmd[4:]
295 if not path:
291 if not path:
296 path = util.findexe(cmd)
292 path = util.findexe(cmd)
297 if path is None:
293 if path is None:
298 path = filemerge.findexternaltool(ui, cmd) or cmd
294 path = filemerge.findexternaltool(ui, cmd) or cmd
299 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
295 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
300 cmdline = util.shellquote(path)
296 cmdline = util.shellquote(path)
301 if diffopts:
297 if diffopts:
302 cmdline += ' ' + diffopts
298 cmdline += ' ' + diffopts
303 elif cmd.startswith('opts.'):
299 elif cmd.startswith('opts.'):
304 continue
300 continue
305 else:
301 else:
306 if path:
302 if path:
307 # case "cmd = path opts"
303 # case "cmd = path opts"
308 cmdline = path
304 cmdline = path
309 diffopts = len(shlex.split(cmdline)) > 1
305 diffopts = len(shlex.split(cmdline)) > 1
310 else:
306 else:
311 # case "cmd ="
307 # case "cmd ="
312 path = util.findexe(cmd)
308 path = util.findexe(cmd)
313 if path is None:
309 if path is None:
314 path = filemerge.findexternaltool(ui, cmd) or cmd
310 path = filemerge.findexternaltool(ui, cmd) or cmd
315 cmdline = util.shellquote(path)
311 cmdline = util.shellquote(path)
316 diffopts = False
312 diffopts = False
317 # look for diff arguments in [diff-tools] then [merge-tools]
313 # look for diff arguments in [diff-tools] then [merge-tools]
318 if not diffopts:
314 if not diffopts:
319 args = ui.config('diff-tools', cmd+'.diffargs') or \
315 args = ui.config('diff-tools', cmd+'.diffargs') or \
320 ui.config('merge-tools', cmd+'.diffargs')
316 ui.config('merge-tools', cmd+'.diffargs')
321 if args:
317 if args:
322 cmdline += ' ' + args
318 cmdline += ' ' + args
323 def save(cmdline):
319 def save(cmdline):
324 '''use closure to save diff command to use'''
320 '''use closure to save diff command to use'''
325 def mydiff(ui, repo, *pats, **opts):
321 def mydiff(ui, repo, *pats, **opts):
326 options = ' '.join(map(util.shellquote, opts['option']))
322 options = ' '.join(map(util.shellquote, opts['option']))
327 if options:
323 if options:
328 options = ' ' + options
324 options = ' ' + options
329 return dodiff(ui, repo, cmdline + options, pats, opts)
325 return dodiff(ui, repo, cmdline + options, pats, opts)
330 doc = _('''\
326 doc = _('''\
331 use %(path)s to diff repository (or selected files)
327 use %(path)s to diff repository (or selected files)
332
328
333 Show differences between revisions for the specified files, using
329 Show differences between revisions for the specified files, using
334 the %(path)s program.
330 the %(path)s program.
335
331
336 When two revision arguments are given, then changes are shown
332 When two revision arguments are given, then changes are shown
337 between those revisions. If only one revision is specified then
333 between those revisions. If only one revision is specified then
338 that revision is compared to the working directory, and, when no
334 that revision is compared to the working directory, and, when no
339 revisions are specified, the working directory files are compared
335 revisions are specified, the working directory files are compared
340 to its parent.\
336 to its parent.\
341 ''') % {'path': util.uirepr(path)}
337 ''') % {'path': util.uirepr(path)}
342
338
343 # We must translate the docstring right away since it is
339 # We must translate the docstring right away since it is
344 # used as a format string. The string will unfortunately
340 # used as a format string. The string will unfortunately
345 # be translated again in commands.helpcmd and this will
341 # be translated again in commands.helpcmd and this will
346 # fail when the docstring contains non-ASCII characters.
342 # fail when the docstring contains non-ASCII characters.
347 # Decoding the string to a Unicode string here (using the
343 # Decoding the string to a Unicode string here (using the
348 # right encoding) prevents that.
344 # right encoding) prevents that.
349 mydiff.__doc__ = doc.decode(encoding.encoding)
345 mydiff.__doc__ = doc.decode(encoding.encoding)
350 return mydiff
346 return mydiff
351 cmdtable[cmd] = (save(cmdline),
347 cmdtable[cmd] = (save(cmdline),
352 cmdtable['extdiff'][1][1:],
348 cmdtable['extdiff'][1][1:],
353 _('hg %s [OPTION]... [FILE]...') % cmd)
349 _('hg %s [OPTION]... [FILE]...') % cmd)
General Comments 0
You need to be logged in to leave comments. Login now