##// END OF EJS Templates
extdiff: escape filenames with vim/DirDiff and make quoting work with Windows...
Thomas Arendsen Hein -
r16242:55174ab8 stable
parent child Browse files
Show More
@@ -1,93 +1,93 b''
1 ; System-wide Mercurial config file.
1 ; System-wide Mercurial config file.
2 ;
2 ;
3 ; !!! Do Not Edit This File !!!
3 ; !!! Do Not Edit This File !!!
4 ;
4 ;
5 ; This file will be replaced by the installer on every upgrade.
5 ; This file will be replaced by the installer on every upgrade.
6 ; Editing this file can cause strange side effects on Vista.
6 ; Editing this file can cause strange side effects on Vista.
7 ;
7 ;
8 ; http://bitbucket.org/tortoisehg/stable/issue/135
8 ; http://bitbucket.org/tortoisehg/stable/issue/135
9 ;
9 ;
10 ; To change settings you see in this file, override (or enable) them in
10 ; To change settings you see in this file, override (or enable) them in
11 ; your user Mercurial.ini file, where USERNAME is your Windows user name:
11 ; your user Mercurial.ini file, where USERNAME is your Windows user name:
12 ;
12 ;
13 ; XP or older - C:\Documents and Settings\USERNAME\Mercurial.ini
13 ; XP or older - C:\Documents and Settings\USERNAME\Mercurial.ini
14 ; Vista or later - C:\Users\USERNAME\Mercurial.ini
14 ; Vista or later - C:\Users\USERNAME\Mercurial.ini
15
15
16
16
17 [ui]
17 [ui]
18 ; editor used to enter commit logs, etc. Most text editors will work.
18 ; editor used to enter commit logs, etc. Most text editors will work.
19 editor = notepad
19 editor = notepad
20 ; show changed files and be a bit more verbose if True
20 ; show changed files and be a bit more verbose if True
21 ; verbose = True
21 ; verbose = True
22
22
23 ; username data to appear in commits
23 ; username data to appear in commits
24 ; it usually takes the form: Joe User <joe.user@host.com>
24 ; it usually takes the form: Joe User <joe.user@host.com>
25 ; username = Joe User <j.user@example.com>
25 ; username = Joe User <j.user@example.com>
26
26
27 ; In order to push/pull over ssh you must specify an ssh tool
27 ; In order to push/pull over ssh you must specify an ssh tool
28 ;ssh = "C:\Progra~1\TortoiseSVN\bin\TortoisePlink.exe" -ssh -2
28 ;ssh = "C:\Progra~1\TortoiseSVN\bin\TortoisePlink.exe" -ssh -2
29 ;ssh = C:\cygwin\bin\ssh
29 ;ssh = C:\cygwin\bin\ssh
30
30
31 ;
31 ;
32 ; For more information about mercurial extensions, start here
32 ; For more information about mercurial extensions, start here
33 ; http://www.selenic.com/mercurial/wiki/index.cgi/UsingExtensions
33 ; http://www.selenic.com/mercurial/wiki/index.cgi/UsingExtensions
34 ;
34 ;
35 ; Extensions shipped with Mercurial
35 ; Extensions shipped with Mercurial
36 ;
36 ;
37 [extensions]
37 [extensions]
38 ;acl =
38 ;acl =
39 ;alias =
39 ;alias =
40 ;bugzilla =
40 ;bugzilla =
41 ;children =
41 ;children =
42 ;churn =
42 ;churn =
43 ;color =
43 ;color =
44 ;convert =
44 ;convert =
45 ;eol =
45 ;eol =
46 ;extdiff =
46 ;extdiff =
47 ;fetch =
47 ;fetch =
48 ;gpg =
48 ;gpg =
49 ;graphlog =
49 ;graphlog =
50 ;hgcia =
50 ;hgcia =
51 ;hgk =
51 ;hgk =
52 ;highlight =
52 ;highlight =
53 ;interhg =
53 ;interhg =
54 ;keyword =
54 ;keyword =
55 ;mq =
55 ;mq =
56 ;notify =
56 ;notify =
57 ;pager =
57 ;pager =
58 ;patchbomb =
58 ;patchbomb =
59 ;progress =
59 ;progress =
60 ;purge =
60 ;purge =
61 ;rebase =
61 ;rebase =
62 ;record =
62 ;record =
63 ;transplant =
63 ;transplant =
64 ;win32mbcs =
64 ;win32mbcs =
65 ;zeroconf =
65 ;zeroconf =
66
66
67 ;
67 ;
68 ; Define external diff commands
68 ; Define external diff commands
69 ;
69 ;
70 [extdiff]
70 [extdiff]
71 ;cmd.bc3diff = C:\Program Files\Beyond Compare 3\BCompare.exe
71 ;cmd.bc3diff = C:\Program Files\Beyond Compare 3\BCompare.exe
72 ;cmd.vdiff = C:\Progra~1\TortoiseSVN\bin\TortoiseMerge.exe
72 ;cmd.vdiff = C:\Progra~1\TortoiseSVN\bin\TortoiseMerge.exe
73 ;cmd.vimdiff = gvim.exe
73 ;cmd.vimdiff = gvim.exe
74 ;opts.vimdiff = -f '+next' '+execute "DirDiff ".argv(0)." ".argv(1)'
74 ;opts.vimdiff = -f "+next" "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
75
75
76
76
77 [hgk]
77 [hgk]
78 ; Replace the following with your path to hgk, uncomment it and
78 ; Replace the following with your path to hgk, uncomment it and
79 ; install ActiveTcl (or another win32 port like tclkit)
79 ; install ActiveTcl (or another win32 port like tclkit)
80 ; path="C:\Program Files\Mercurial\Contrib\hgk.tcl"
80 ; path="C:\Program Files\Mercurial\Contrib\hgk.tcl"
81 ; vdiff=vdiff
81 ; vdiff=vdiff
82
82
83
83
84 ;
84 ;
85 ; The git extended diff format can represent binary files, file
85 ; The git extended diff format can represent binary files, file
86 ; permission changes, and rename information that the normal patch format
86 ; permission changes, and rename information that the normal patch format
87 ; cannot describe. However it is also not compatible with tools which
87 ; cannot describe. However it is also not compatible with tools which
88 ; expect normal patches. so enable git patches at your own risk.
88 ; expect normal patches. so enable git patches at your own risk.
89 ;
89 ;
90 [diff]
90 [diff]
91 ;git = false
91 ;git = false
92 ;nodates = false
92 ;nodates = false
93
93
@@ -1,328 +1,329 b''
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 vdiff, runs kdiff3
26 # add new command called vdiff, runs kdiff3
27 vdiff = kdiff3
27 vdiff = kdiff3
28
28
29 # add new command called meld, runs meld (no need to name twice)
29 # add new command called meld, runs meld (no need to name twice)
30 meld =
30 meld =
31
31
32 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
32 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
33 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
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
34 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
35 # your .vimrc
35 # your .vimrc
36 vimdiff = gvim -f '+next' '+execute "DirDiff" argv(0) argv(1)'
36 vimdiff = gvim -f "+next" \\
37 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
37
38
38 Tool arguments can include variables that are expanded at runtime::
39 Tool arguments can include variables that are expanded at runtime::
39
40
40 $parent1, $plabel1 - filename, descriptive label of first parent
41 $parent1, $plabel1 - filename, descriptive label of first parent
41 $child, $clabel - filename, descriptive label of child revision
42 $child, $clabel - filename, descriptive label of child revision
42 $parent2, $plabel2 - filename, descriptive label of second parent
43 $parent2, $plabel2 - filename, descriptive label of second parent
43 $root - repository root
44 $root - repository root
44 $parent is an alias for $parent1.
45 $parent is an alias for $parent1.
45
46
46 The extdiff extension will look in your [diff-tools] and [merge-tools]
47 The extdiff extension will look in your [diff-tools] and [merge-tools]
47 sections for diff tool arguments, when none are specified in [extdiff].
48 sections for diff tool arguments, when none are specified in [extdiff].
48
49
49 ::
50 ::
50
51
51 [extdiff]
52 [extdiff]
52 kdiff3 =
53 kdiff3 =
53
54
54 [diff-tools]
55 [diff-tools]
55 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
56 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
56
57
57 You can use -I/-X and list of file or directory names like normal
58 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
59 :hg:`diff` command. The extdiff extension makes snapshots of only
59 needed files, so running the external diff program will actually be
60 needed files, so running the external diff program will actually be
60 pretty fast (at least faster than having to compare the entire tree).
61 pretty fast (at least faster than having to compare the entire tree).
61 '''
62 '''
62
63
63 from mercurial.i18n import _
64 from mercurial.i18n import _
64 from mercurial.node import short, nullid
65 from mercurial.node import short, nullid
65 from mercurial import scmutil, scmutil, util, commands, encoding
66 from mercurial import scmutil, scmutil, util, commands, encoding
66 import os, shlex, shutil, tempfile, re
67 import os, shlex, shutil, tempfile, re
67
68
68 def snapshot(ui, repo, files, node, tmproot):
69 def snapshot(ui, repo, files, node, tmproot):
69 '''snapshot files as of some revision
70 '''snapshot files as of some revision
70 if not using snapshot, -I/-X does not work and recursive diff
71 if not using snapshot, -I/-X does not work and recursive diff
71 in tools like kdiff3 and meld displays too many files.'''
72 in tools like kdiff3 and meld displays too many files.'''
72 dirname = os.path.basename(repo.root)
73 dirname = os.path.basename(repo.root)
73 if dirname == "":
74 if dirname == "":
74 dirname = "root"
75 dirname = "root"
75 if node is not None:
76 if node is not None:
76 dirname = '%s.%s' % (dirname, short(node))
77 dirname = '%s.%s' % (dirname, short(node))
77 base = os.path.join(tmproot, dirname)
78 base = os.path.join(tmproot, dirname)
78 os.mkdir(base)
79 os.mkdir(base)
79 if node is not None:
80 if node is not None:
80 ui.note(_('making snapshot of %d files from rev %s\n') %
81 ui.note(_('making snapshot of %d files from rev %s\n') %
81 (len(files), short(node)))
82 (len(files), short(node)))
82 else:
83 else:
83 ui.note(_('making snapshot of %d files from working directory\n') %
84 ui.note(_('making snapshot of %d files from working directory\n') %
84 (len(files)))
85 (len(files)))
85 wopener = scmutil.opener(base)
86 wopener = scmutil.opener(base)
86 fns_and_mtime = []
87 fns_and_mtime = []
87 ctx = repo[node]
88 ctx = repo[node]
88 for fn in files:
89 for fn in files:
89 wfn = util.pconvert(fn)
90 wfn = util.pconvert(fn)
90 if not wfn in ctx:
91 if not wfn in ctx:
91 # File doesn't exist; could be a bogus modify
92 # File doesn't exist; could be a bogus modify
92 continue
93 continue
93 ui.note(' %s\n' % wfn)
94 ui.note(' %s\n' % wfn)
94 dest = os.path.join(base, wfn)
95 dest = os.path.join(base, wfn)
95 fctx = ctx[wfn]
96 fctx = ctx[wfn]
96 data = repo.wwritedata(wfn, fctx.data())
97 data = repo.wwritedata(wfn, fctx.data())
97 if 'l' in fctx.flags():
98 if 'l' in fctx.flags():
98 wopener.symlink(data, wfn)
99 wopener.symlink(data, wfn)
99 else:
100 else:
100 wopener.write(wfn, data)
101 wopener.write(wfn, data)
101 if 'x' in fctx.flags():
102 if 'x' in fctx.flags():
102 util.setflags(dest, False, True)
103 util.setflags(dest, False, True)
103 if node is None:
104 if node is None:
104 fns_and_mtime.append((dest, repo.wjoin(fn),
105 fns_and_mtime.append((dest, repo.wjoin(fn),
105 os.lstat(dest).st_mtime))
106 os.lstat(dest).st_mtime))
106 return dirname, fns_and_mtime
107 return dirname, fns_and_mtime
107
108
108 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
109 def dodiff(ui, repo, diffcmd, diffopts, pats, opts):
109 '''Do the actuall diff:
110 '''Do the actuall diff:
110
111
111 - copy to a temp structure if diffing 2 internal revisions
112 - copy to a temp structure if diffing 2 internal revisions
112 - copy to a temp structure if diffing working revision with
113 - copy to a temp structure if diffing working revision with
113 another one and more than 1 file is changed
114 another one and more than 1 file is changed
114 - just invoke the diff for a single file in the working dir
115 - just invoke the diff for a single file in the working dir
115 '''
116 '''
116
117
117 revs = opts.get('rev')
118 revs = opts.get('rev')
118 change = opts.get('change')
119 change = opts.get('change')
119 args = ' '.join(diffopts)
120 args = ' '.join(diffopts)
120 do3way = '$parent2' in args
121 do3way = '$parent2' in args
121
122
122 if revs and change:
123 if revs and change:
123 msg = _('cannot specify --rev and --change at the same time')
124 msg = _('cannot specify --rev and --change at the same time')
124 raise util.Abort(msg)
125 raise util.Abort(msg)
125 elif change:
126 elif change:
126 node2 = scmutil.revsingle(repo, change, None).node()
127 node2 = scmutil.revsingle(repo, change, None).node()
127 node1a, node1b = repo.changelog.parents(node2)
128 node1a, node1b = repo.changelog.parents(node2)
128 else:
129 else:
129 node1a, node2 = scmutil.revpair(repo, revs)
130 node1a, node2 = scmutil.revpair(repo, revs)
130 if not revs:
131 if not revs:
131 node1b = repo.dirstate.p2()
132 node1b = repo.dirstate.p2()
132 else:
133 else:
133 node1b = nullid
134 node1b = nullid
134
135
135 # Disable 3-way merge if there is only one parent
136 # Disable 3-way merge if there is only one parent
136 if do3way:
137 if do3way:
137 if node1b == nullid:
138 if node1b == nullid:
138 do3way = False
139 do3way = False
139
140
140 matcher = scmutil.match(repo[node2], pats, opts)
141 matcher = scmutil.match(repo[node2], pats, opts)
141 mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3])
142 mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher)[:3])
142 if do3way:
143 if do3way:
143 mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[:3])
144 mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher)[:3])
144 else:
145 else:
145 mod_b, add_b, rem_b = set(), set(), set()
146 mod_b, add_b, rem_b = set(), set(), set()
146 modadd = mod_a | add_a | mod_b | add_b
147 modadd = mod_a | add_a | mod_b | add_b
147 common = modadd | rem_a | rem_b
148 common = modadd | rem_a | rem_b
148 if not common:
149 if not common:
149 return 0
150 return 0
150
151
151 tmproot = tempfile.mkdtemp(prefix='extdiff.')
152 tmproot = tempfile.mkdtemp(prefix='extdiff.')
152 try:
153 try:
153 # Always make a copy of node1a (and node1b, if applicable)
154 # Always make a copy of node1a (and node1b, if applicable)
154 dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
155 dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
155 dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot)[0]
156 dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot)[0]
156 rev1a = '@%d' % repo[node1a].rev()
157 rev1a = '@%d' % repo[node1a].rev()
157 if do3way:
158 if do3way:
158 dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
159 dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
159 dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot)[0]
160 dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot)[0]
160 rev1b = '@%d' % repo[node1b].rev()
161 rev1b = '@%d' % repo[node1b].rev()
161 else:
162 else:
162 dir1b = None
163 dir1b = None
163 rev1b = ''
164 rev1b = ''
164
165
165 fns_and_mtime = []
166 fns_and_mtime = []
166
167
167 # If node2 in not the wc or there is >1 change, copy it
168 # If node2 in not the wc or there is >1 change, copy it
168 dir2root = ''
169 dir2root = ''
169 rev2 = ''
170 rev2 = ''
170 if node2:
171 if node2:
171 dir2 = snapshot(ui, repo, modadd, node2, tmproot)[0]
172 dir2 = snapshot(ui, repo, modadd, node2, tmproot)[0]
172 rev2 = '@%d' % repo[node2].rev()
173 rev2 = '@%d' % repo[node2].rev()
173 elif len(common) > 1:
174 elif len(common) > 1:
174 #we only actually need to get the files to copy back to
175 #we only actually need to get the files to copy back to
175 #the working dir in this case (because the other cases
176 #the working dir in this case (because the other cases
176 #are: diffing 2 revisions or single file -- in which case
177 #are: diffing 2 revisions or single file -- in which case
177 #the file is already directly passed to the diff tool).
178 #the file is already directly passed to the diff tool).
178 dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot)
179 dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot)
179 else:
180 else:
180 # This lets the diff tool open the changed file directly
181 # This lets the diff tool open the changed file directly
181 dir2 = ''
182 dir2 = ''
182 dir2root = repo.root
183 dir2root = repo.root
183
184
184 label1a = rev1a
185 label1a = rev1a
185 label1b = rev1b
186 label1b = rev1b
186 label2 = rev2
187 label2 = rev2
187
188
188 # If only one change, diff the files instead of the directories
189 # If only one change, diff the files instead of the directories
189 # Handle bogus modifies correctly by checking if the files exist
190 # Handle bogus modifies correctly by checking if the files exist
190 if len(common) == 1:
191 if len(common) == 1:
191 common_file = util.localpath(common.pop())
192 common_file = util.localpath(common.pop())
192 dir1a = os.path.join(tmproot, dir1a, common_file)
193 dir1a = os.path.join(tmproot, dir1a, common_file)
193 label1a = common_file + rev1a
194 label1a = common_file + rev1a
194 if not os.path.isfile(dir1a):
195 if not os.path.isfile(dir1a):
195 dir1a = os.devnull
196 dir1a = os.devnull
196 if do3way:
197 if do3way:
197 dir1b = os.path.join(tmproot, dir1b, common_file)
198 dir1b = os.path.join(tmproot, dir1b, common_file)
198 label1b = common_file + rev1b
199 label1b = common_file + rev1b
199 if not os.path.isfile(dir1b):
200 if not os.path.isfile(dir1b):
200 dir1b = os.devnull
201 dir1b = os.devnull
201 dir2 = os.path.join(dir2root, dir2, common_file)
202 dir2 = os.path.join(dir2root, dir2, common_file)
202 label2 = common_file + rev2
203 label2 = common_file + rev2
203
204
204 # Function to quote file/dir names in the argument string.
205 # Function to quote file/dir names in the argument string.
205 # When not operating in 3-way mode, an empty string is
206 # When not operating in 3-way mode, an empty string is
206 # returned for parent2
207 # returned for parent2
207 replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b,
208 replace = dict(parent=dir1a, parent1=dir1a, parent2=dir1b,
208 plabel1=label1a, plabel2=label1b,
209 plabel1=label1a, plabel2=label1b,
209 clabel=label2, child=dir2,
210 clabel=label2, child=dir2,
210 root=repo.root)
211 root=repo.root)
211 def quote(match):
212 def quote(match):
212 key = match.group()[1:]
213 key = match.group()[1:]
213 if not do3way and key == 'parent2':
214 if not do3way and key == 'parent2':
214 return ''
215 return ''
215 return util.shellquote(replace[key])
216 return util.shellquote(replace[key])
216
217
217 # Match parent2 first, so 'parent1?' will match both parent1 and parent
218 # Match parent2 first, so 'parent1?' will match both parent1 and parent
218 regex = '\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)'
219 regex = '\$(parent2|parent1?|child|plabel1|plabel2|clabel|root)'
219 if not do3way and not re.search(regex, args):
220 if not do3way and not re.search(regex, args):
220 args += ' $parent1 $child'
221 args += ' $parent1 $child'
221 args = re.sub(regex, quote, args)
222 args = re.sub(regex, quote, args)
222 cmdline = util.shellquote(diffcmd) + ' ' + args
223 cmdline = util.shellquote(diffcmd) + ' ' + args
223
224
224 ui.debug('running %r in %s\n' % (cmdline, tmproot))
225 ui.debug('running %r in %s\n' % (cmdline, tmproot))
225 util.system(cmdline, cwd=tmproot, out=ui.fout)
226 util.system(cmdline, cwd=tmproot, out=ui.fout)
226
227
227 for copy_fn, working_fn, mtime in fns_and_mtime:
228 for copy_fn, working_fn, mtime in fns_and_mtime:
228 if os.lstat(copy_fn).st_mtime != mtime:
229 if os.lstat(copy_fn).st_mtime != mtime:
229 ui.debug('file changed while diffing. '
230 ui.debug('file changed while diffing. '
230 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
231 'Overwriting: %s (src: %s)\n' % (working_fn, copy_fn))
231 util.copyfile(copy_fn, working_fn)
232 util.copyfile(copy_fn, working_fn)
232
233
233 return 1
234 return 1
234 finally:
235 finally:
235 ui.note(_('cleaning up temp directory\n'))
236 ui.note(_('cleaning up temp directory\n'))
236 shutil.rmtree(tmproot)
237 shutil.rmtree(tmproot)
237
238
238 def extdiff(ui, repo, *pats, **opts):
239 def extdiff(ui, repo, *pats, **opts):
239 '''use external program to diff repository (or selected files)
240 '''use external program to diff repository (or selected files)
240
241
241 Show differences between revisions for the specified files, using
242 Show differences between revisions for the specified files, using
242 an external program. The default program used is diff, with
243 an external program. The default program used is diff, with
243 default options "-Npru".
244 default options "-Npru".
244
245
245 To select a different program, use the -p/--program option. The
246 To select a different program, use the -p/--program option. The
246 program will be passed the names of two directories to compare. To
247 program will be passed the names of two directories to compare. To
247 pass additional options to the program, use -o/--option. These
248 pass additional options to the program, use -o/--option. These
248 will be passed before the names of the directories to compare.
249 will be passed before the names of the directories to compare.
249
250
250 When two revision arguments are given, then changes are shown
251 When two revision arguments are given, then changes are shown
251 between those revisions. If only one revision is specified then
252 between those revisions. If only one revision is specified then
252 that revision is compared to the working directory, and, when no
253 that revision is compared to the working directory, and, when no
253 revisions are specified, the working directory files are compared
254 revisions are specified, the working directory files are compared
254 to its parent.'''
255 to its parent.'''
255 program = opts.get('program')
256 program = opts.get('program')
256 option = opts.get('option')
257 option = opts.get('option')
257 if not program:
258 if not program:
258 program = 'diff'
259 program = 'diff'
259 option = option or ['-Npru']
260 option = option or ['-Npru']
260 return dodiff(ui, repo, program, option, pats, opts)
261 return dodiff(ui, repo, program, option, pats, opts)
261
262
262 cmdtable = {
263 cmdtable = {
263 "extdiff":
264 "extdiff":
264 (extdiff,
265 (extdiff,
265 [('p', 'program', '',
266 [('p', 'program', '',
266 _('comparison program to run'), _('CMD')),
267 _('comparison program to run'), _('CMD')),
267 ('o', 'option', [],
268 ('o', 'option', [],
268 _('pass option to comparison program'), _('OPT')),
269 _('pass option to comparison program'), _('OPT')),
269 ('r', 'rev', [],
270 ('r', 'rev', [],
270 _('revision'), _('REV')),
271 _('revision'), _('REV')),
271 ('c', 'change', '',
272 ('c', 'change', '',
272 _('change made by revision'), _('REV')),
273 _('change made by revision'), _('REV')),
273 ] + commands.walkopts,
274 ] + commands.walkopts,
274 _('hg extdiff [OPT]... [FILE]...')),
275 _('hg extdiff [OPT]... [FILE]...')),
275 }
276 }
276
277
277 def uisetup(ui):
278 def uisetup(ui):
278 for cmd, path in ui.configitems('extdiff'):
279 for cmd, path in ui.configitems('extdiff'):
279 if cmd.startswith('cmd.'):
280 if cmd.startswith('cmd.'):
280 cmd = cmd[4:]
281 cmd = cmd[4:]
281 if not path:
282 if not path:
282 path = cmd
283 path = cmd
283 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
284 diffopts = ui.config('extdiff', 'opts.' + cmd, '')
284 diffopts = diffopts and [diffopts] or []
285 diffopts = diffopts and [diffopts] or []
285 elif cmd.startswith('opts.'):
286 elif cmd.startswith('opts.'):
286 continue
287 continue
287 else:
288 else:
288 # command = path opts
289 # command = path opts
289 if path:
290 if path:
290 diffopts = shlex.split(path)
291 diffopts = shlex.split(path)
291 path = diffopts.pop(0)
292 path = diffopts.pop(0)
292 else:
293 else:
293 path, diffopts = cmd, []
294 path, diffopts = cmd, []
294 # look for diff arguments in [diff-tools] then [merge-tools]
295 # look for diff arguments in [diff-tools] then [merge-tools]
295 if diffopts == []:
296 if diffopts == []:
296 args = ui.config('diff-tools', cmd+'.diffargs') or \
297 args = ui.config('diff-tools', cmd+'.diffargs') or \
297 ui.config('merge-tools', cmd+'.diffargs')
298 ui.config('merge-tools', cmd+'.diffargs')
298 if args:
299 if args:
299 diffopts = shlex.split(args)
300 diffopts = shlex.split(args)
300 def save(cmd, path, diffopts):
301 def save(cmd, path, diffopts):
301 '''use closure to save diff command to use'''
302 '''use closure to save diff command to use'''
302 def mydiff(ui, repo, *pats, **opts):
303 def mydiff(ui, repo, *pats, **opts):
303 return dodiff(ui, repo, path, diffopts + opts['option'],
304 return dodiff(ui, repo, path, diffopts + opts['option'],
304 pats, opts)
305 pats, opts)
305 doc = _('''\
306 doc = _('''\
306 use %(path)s to diff repository (or selected files)
307 use %(path)s to diff repository (or selected files)
307
308
308 Show differences between revisions for the specified files, using
309 Show differences between revisions for the specified files, using
309 the %(path)s program.
310 the %(path)s program.
310
311
311 When two revision arguments are given, then changes are shown
312 When two revision arguments are given, then changes are shown
312 between those revisions. If only one revision is specified then
313 between those revisions. If only one revision is specified then
313 that revision is compared to the working directory, and, when no
314 that revision is compared to the working directory, and, when no
314 revisions are specified, the working directory files are compared
315 revisions are specified, the working directory files are compared
315 to its parent.\
316 to its parent.\
316 ''') % dict(path=util.uirepr(path))
317 ''') % dict(path=util.uirepr(path))
317
318
318 # We must translate the docstring right away since it is
319 # We must translate the docstring right away since it is
319 # used as a format string. The string will unfortunately
320 # used as a format string. The string will unfortunately
320 # be translated again in commands.helpcmd and this will
321 # be translated again in commands.helpcmd and this will
321 # fail when the docstring contains non-ASCII characters.
322 # fail when the docstring contains non-ASCII characters.
322 # Decoding the string to a Unicode string here (using the
323 # Decoding the string to a Unicode string here (using the
323 # right encoding) prevents that.
324 # right encoding) prevents that.
324 mydiff.__doc__ = doc.decode(encoding.encoding)
325 mydiff.__doc__ = doc.decode(encoding.encoding)
325 return mydiff
326 return mydiff
326 cmdtable[cmd] = (save(cmd, path, diffopts),
327 cmdtable[cmd] = (save(cmd, path, diffopts),
327 cmdtable['extdiff'][1][1:],
328 cmdtable['extdiff'][1][1:],
328 _('hg %s [OPTION]... [FILE]...') % cmd)
329 _('hg %s [OPTION]... [FILE]...') % cmd)
@@ -1,479 +1,480 b''
1 Test basic extension support
1 Test basic extension support
2
2
3 $ "$TESTDIR/hghave" no-outer-repo || exit 80
3 $ "$TESTDIR/hghave" no-outer-repo || exit 80
4
4
5 $ cat > foobar.py <<EOF
5 $ cat > foobar.py <<EOF
6 > import os
6 > import os
7 > from mercurial import commands
7 > from mercurial import commands
8 >
8 >
9 > def uisetup(ui):
9 > def uisetup(ui):
10 > ui.write("uisetup called\\n")
10 > ui.write("uisetup called\\n")
11 >
11 >
12 > def reposetup(ui, repo):
12 > def reposetup(ui, repo):
13 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
13 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
14 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
14 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
15 >
15 >
16 > def foo(ui, *args, **kwargs):
16 > def foo(ui, *args, **kwargs):
17 > ui.write("Foo\\n")
17 > ui.write("Foo\\n")
18 >
18 >
19 > def bar(ui, *args, **kwargs):
19 > def bar(ui, *args, **kwargs):
20 > ui.write("Bar\\n")
20 > ui.write("Bar\\n")
21 >
21 >
22 > cmdtable = {
22 > cmdtable = {
23 > "foo": (foo, [], "hg foo"),
23 > "foo": (foo, [], "hg foo"),
24 > "bar": (bar, [], "hg bar"),
24 > "bar": (bar, [], "hg bar"),
25 > }
25 > }
26 >
26 >
27 > commands.norepo += ' bar'
27 > commands.norepo += ' bar'
28 > EOF
28 > EOF
29 $ abspath=`pwd`/foobar.py
29 $ abspath=`pwd`/foobar.py
30
30
31 $ mkdir barfoo
31 $ mkdir barfoo
32 $ cp foobar.py barfoo/__init__.py
32 $ cp foobar.py barfoo/__init__.py
33 $ barfoopath=`pwd`/barfoo
33 $ barfoopath=`pwd`/barfoo
34
34
35 $ hg init a
35 $ hg init a
36 $ cd a
36 $ cd a
37 $ echo foo > file
37 $ echo foo > file
38 $ hg add file
38 $ hg add file
39 $ hg commit -m 'add file'
39 $ hg commit -m 'add file'
40
40
41 $ echo '[extensions]' >> $HGRCPATH
41 $ echo '[extensions]' >> $HGRCPATH
42 $ echo "foobar = $abspath" >> $HGRCPATH
42 $ echo "foobar = $abspath" >> $HGRCPATH
43 $ hg foo
43 $ hg foo
44 uisetup called
44 uisetup called
45 reposetup called for a
45 reposetup called for a
46 ui == repo.ui
46 ui == repo.ui
47 Foo
47 Foo
48
48
49 $ cd ..
49 $ cd ..
50 $ hg clone a b
50 $ hg clone a b
51 uisetup called
51 uisetup called
52 reposetup called for a
52 reposetup called for a
53 ui == repo.ui
53 ui == repo.ui
54 reposetup called for b
54 reposetup called for b
55 ui == repo.ui
55 ui == repo.ui
56 updating to branch default
56 updating to branch default
57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
58
58
59 $ hg bar
59 $ hg bar
60 uisetup called
60 uisetup called
61 Bar
61 Bar
62 $ echo 'foobar = !' >> $HGRCPATH
62 $ echo 'foobar = !' >> $HGRCPATH
63
63
64 module/__init__.py-style
64 module/__init__.py-style
65
65
66 $ echo "barfoo = $barfoopath" >> $HGRCPATH
66 $ echo "barfoo = $barfoopath" >> $HGRCPATH
67 $ cd a
67 $ cd a
68 $ hg foo
68 $ hg foo
69 uisetup called
69 uisetup called
70 reposetup called for a
70 reposetup called for a
71 ui == repo.ui
71 ui == repo.ui
72 Foo
72 Foo
73 $ echo 'barfoo = !' >> $HGRCPATH
73 $ echo 'barfoo = !' >> $HGRCPATH
74
74
75 Check that extensions are loaded in phases:
75 Check that extensions are loaded in phases:
76
76
77 $ cat > foo.py <<EOF
77 $ cat > foo.py <<EOF
78 > import os
78 > import os
79 > name = os.path.basename(__file__).rsplit('.', 1)[0]
79 > name = os.path.basename(__file__).rsplit('.', 1)[0]
80 > print "1) %s imported" % name
80 > print "1) %s imported" % name
81 > def uisetup(ui):
81 > def uisetup(ui):
82 > print "2) %s uisetup" % name
82 > print "2) %s uisetup" % name
83 > def extsetup():
83 > def extsetup():
84 > print "3) %s extsetup" % name
84 > print "3) %s extsetup" % name
85 > def reposetup(ui, repo):
85 > def reposetup(ui, repo):
86 > print "4) %s reposetup" % name
86 > print "4) %s reposetup" % name
87 > EOF
87 > EOF
88
88
89 $ cp foo.py bar.py
89 $ cp foo.py bar.py
90 $ echo 'foo = foo.py' >> $HGRCPATH
90 $ echo 'foo = foo.py' >> $HGRCPATH
91 $ echo 'bar = bar.py' >> $HGRCPATH
91 $ echo 'bar = bar.py' >> $HGRCPATH
92
92
93 Command with no output, we just want to see the extensions loaded:
93 Command with no output, we just want to see the extensions loaded:
94
94
95 $ hg paths
95 $ hg paths
96 1) foo imported
96 1) foo imported
97 1) bar imported
97 1) bar imported
98 2) foo uisetup
98 2) foo uisetup
99 2) bar uisetup
99 2) bar uisetup
100 3) foo extsetup
100 3) foo extsetup
101 3) bar extsetup
101 3) bar extsetup
102 4) foo reposetup
102 4) foo reposetup
103 4) bar reposetup
103 4) bar reposetup
104
104
105 Check hgweb's load order:
105 Check hgweb's load order:
106
106
107 $ cat > hgweb.cgi <<EOF
107 $ cat > hgweb.cgi <<EOF
108 > #!/usr/bin/env python
108 > #!/usr/bin/env python
109 > from mercurial import demandimport; demandimport.enable()
109 > from mercurial import demandimport; demandimport.enable()
110 > from mercurial.hgweb import hgweb
110 > from mercurial.hgweb import hgweb
111 > from mercurial.hgweb import wsgicgi
111 > from mercurial.hgweb import wsgicgi
112 >
112 >
113 > application = hgweb('.', 'test repo')
113 > application = hgweb('.', 'test repo')
114 > wsgicgi.launch(application)
114 > wsgicgi.launch(application)
115 > EOF
115 > EOF
116
116
117 $ SCRIPT_NAME='/' SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
117 $ SCRIPT_NAME='/' SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
118 > | grep '^[0-9]) ' # ignores HTML output
118 > | grep '^[0-9]) ' # ignores HTML output
119 1) foo imported
119 1) foo imported
120 1) bar imported
120 1) bar imported
121 2) foo uisetup
121 2) foo uisetup
122 2) bar uisetup
122 2) bar uisetup
123 3) foo extsetup
123 3) foo extsetup
124 3) bar extsetup
124 3) bar extsetup
125 4) foo reposetup
125 4) foo reposetup
126 4) bar reposetup
126 4) bar reposetup
127 4) foo reposetup
127 4) foo reposetup
128 4) bar reposetup
128 4) bar reposetup
129
129
130 $ echo 'foo = !' >> $HGRCPATH
130 $ echo 'foo = !' >> $HGRCPATH
131 $ echo 'bar = !' >> $HGRCPATH
131 $ echo 'bar = !' >> $HGRCPATH
132
132
133 $ cd ..
133 $ cd ..
134
134
135 $ cat > empty.py <<EOF
135 $ cat > empty.py <<EOF
136 > '''empty cmdtable
136 > '''empty cmdtable
137 > '''
137 > '''
138 > cmdtable = {}
138 > cmdtable = {}
139 > EOF
139 > EOF
140 $ emptypath=`pwd`/empty.py
140 $ emptypath=`pwd`/empty.py
141 $ echo "empty = $emptypath" >> $HGRCPATH
141 $ echo "empty = $emptypath" >> $HGRCPATH
142 $ hg help empty
142 $ hg help empty
143 empty extension - empty cmdtable
143 empty extension - empty cmdtable
144
144
145 no commands defined
145 no commands defined
146
146
147 $ echo 'empty = !' >> $HGRCPATH
147 $ echo 'empty = !' >> $HGRCPATH
148
148
149 $ cat > debugextension.py <<EOF
149 $ cat > debugextension.py <<EOF
150 > '''only debugcommands
150 > '''only debugcommands
151 > '''
151 > '''
152 > def debugfoobar(ui, repo, *args, **opts):
152 > def debugfoobar(ui, repo, *args, **opts):
153 > "yet another debug command"
153 > "yet another debug command"
154 > pass
154 > pass
155 >
155 >
156 > def foo(ui, repo, *args, **opts):
156 > def foo(ui, repo, *args, **opts):
157 > """yet another foo command
157 > """yet another foo command
158 >
158 >
159 > This command has been DEPRECATED since forever.
159 > This command has been DEPRECATED since forever.
160 > """
160 > """
161 > pass
161 > pass
162 >
162 >
163 > cmdtable = {
163 > cmdtable = {
164 > "debugfoobar": (debugfoobar, (), "hg debugfoobar"),
164 > "debugfoobar": (debugfoobar, (), "hg debugfoobar"),
165 > "foo": (foo, (), "hg foo")
165 > "foo": (foo, (), "hg foo")
166 > }
166 > }
167 > EOF
167 > EOF
168 $ debugpath=`pwd`/debugextension.py
168 $ debugpath=`pwd`/debugextension.py
169 $ echo "debugextension = $debugpath" >> $HGRCPATH
169 $ echo "debugextension = $debugpath" >> $HGRCPATH
170
170
171 $ hg help debugextension
171 $ hg help debugextension
172 debugextension extension - only debugcommands
172 debugextension extension - only debugcommands
173
173
174 no commands defined
174 no commands defined
175
175
176 $ hg --verbose help debugextension
176 $ hg --verbose help debugextension
177 debugextension extension - only debugcommands
177 debugextension extension - only debugcommands
178
178
179 list of commands:
179 list of commands:
180
180
181 foo:
181 foo:
182 yet another foo command
182 yet another foo command
183
183
184 global options:
184 global options:
185
185
186 -R --repository REPO repository root directory or name of overlay bundle
186 -R --repository REPO repository root directory or name of overlay bundle
187 file
187 file
188 --cwd DIR change working directory
188 --cwd DIR change working directory
189 -y --noninteractive do not prompt, automatically pick the first choice for
189 -y --noninteractive do not prompt, automatically pick the first choice for
190 all prompts
190 all prompts
191 -q --quiet suppress output
191 -q --quiet suppress output
192 -v --verbose enable additional output
192 -v --verbose enable additional output
193 --config CONFIG [+] set/override config option (use 'section.name=value')
193 --config CONFIG [+] set/override config option (use 'section.name=value')
194 --debug enable debugging output
194 --debug enable debugging output
195 --debugger start debugger
195 --debugger start debugger
196 --encoding ENCODE set the charset encoding (default: ascii)
196 --encoding ENCODE set the charset encoding (default: ascii)
197 --encodingmode MODE set the charset encoding mode (default: strict)
197 --encodingmode MODE set the charset encoding mode (default: strict)
198 --traceback always print a traceback on exception
198 --traceback always print a traceback on exception
199 --time time how long the command takes
199 --time time how long the command takes
200 --profile print command execution profile
200 --profile print command execution profile
201 --version output version information and exit
201 --version output version information and exit
202 -h --help display help and exit
202 -h --help display help and exit
203
203
204 [+] marked option can be specified multiple times
204 [+] marked option can be specified multiple times
205
205
206 $ hg --debug help debugextension
206 $ hg --debug help debugextension
207 debugextension extension - only debugcommands
207 debugextension extension - only debugcommands
208
208
209 list of commands:
209 list of commands:
210
210
211 debugfoobar:
211 debugfoobar:
212 yet another debug command
212 yet another debug command
213 foo:
213 foo:
214 yet another foo command
214 yet another foo command
215
215
216 global options:
216 global options:
217
217
218 -R --repository REPO repository root directory or name of overlay bundle
218 -R --repository REPO repository root directory or name of overlay bundle
219 file
219 file
220 --cwd DIR change working directory
220 --cwd DIR change working directory
221 -y --noninteractive do not prompt, automatically pick the first choice for
221 -y --noninteractive do not prompt, automatically pick the first choice for
222 all prompts
222 all prompts
223 -q --quiet suppress output
223 -q --quiet suppress output
224 -v --verbose enable additional output
224 -v --verbose enable additional output
225 --config CONFIG [+] set/override config option (use 'section.name=value')
225 --config CONFIG [+] set/override config option (use 'section.name=value')
226 --debug enable debugging output
226 --debug enable debugging output
227 --debugger start debugger
227 --debugger start debugger
228 --encoding ENCODE set the charset encoding (default: ascii)
228 --encoding ENCODE set the charset encoding (default: ascii)
229 --encodingmode MODE set the charset encoding mode (default: strict)
229 --encodingmode MODE set the charset encoding mode (default: strict)
230 --traceback always print a traceback on exception
230 --traceback always print a traceback on exception
231 --time time how long the command takes
231 --time time how long the command takes
232 --profile print command execution profile
232 --profile print command execution profile
233 --version output version information and exit
233 --version output version information and exit
234 -h --help display help and exit
234 -h --help display help and exit
235
235
236 [+] marked option can be specified multiple times
236 [+] marked option can be specified multiple times
237 $ echo 'debugextension = !' >> $HGRCPATH
237 $ echo 'debugextension = !' >> $HGRCPATH
238
238
239 Extension module help vs command help:
239 Extension module help vs command help:
240
240
241 $ echo 'extdiff =' >> $HGRCPATH
241 $ echo 'extdiff =' >> $HGRCPATH
242 $ hg help extdiff
242 $ hg help extdiff
243 hg extdiff [OPT]... [FILE]...
243 hg extdiff [OPT]... [FILE]...
244
244
245 use external program to diff repository (or selected files)
245 use external program to diff repository (or selected files)
246
246
247 Show differences between revisions for the specified files, using an
247 Show differences between revisions for the specified files, using an
248 external program. The default program used is diff, with default options
248 external program. The default program used is diff, with default options
249 "-Npru".
249 "-Npru".
250
250
251 To select a different program, use the -p/--program option. The program
251 To select a different program, use the -p/--program option. The program
252 will be passed the names of two directories to compare. To pass additional
252 will be passed the names of two directories to compare. To pass additional
253 options to the program, use -o/--option. These will be passed before the
253 options to the program, use -o/--option. These will be passed before the
254 names of the directories to compare.
254 names of the directories to compare.
255
255
256 When two revision arguments are given, then changes are shown between
256 When two revision arguments are given, then changes are shown between
257 those revisions. If only one revision is specified then that revision is
257 those revisions. If only one revision is specified then that revision is
258 compared to the working directory, and, when no revisions are specified,
258 compared to the working directory, and, when no revisions are specified,
259 the working directory files are compared to its parent.
259 the working directory files are compared to its parent.
260
260
261 use "hg help -e extdiff" to show help for the extdiff extension
261 use "hg help -e extdiff" to show help for the extdiff extension
262
262
263 options:
263 options:
264
264
265 -p --program CMD comparison program to run
265 -p --program CMD comparison program to run
266 -o --option OPT [+] pass option to comparison program
266 -o --option OPT [+] pass option to comparison program
267 -r --rev REV [+] revision
267 -r --rev REV [+] revision
268 -c --change REV change made by revision
268 -c --change REV change made by revision
269 -I --include PATTERN [+] include names matching the given patterns
269 -I --include PATTERN [+] include names matching the given patterns
270 -X --exclude PATTERN [+] exclude names matching the given patterns
270 -X --exclude PATTERN [+] exclude names matching the given patterns
271
271
272 [+] marked option can be specified multiple times
272 [+] marked option can be specified multiple times
273
273
274 use "hg -v help extdiff" to show more info
274 use "hg -v help extdiff" to show more info
275
275
276 $ hg help --extension extdiff
276 $ hg help --extension extdiff
277 extdiff extension - command to allow external programs to compare revisions
277 extdiff extension - command to allow external programs to compare revisions
278
278
279 The extdiff Mercurial extension allows you to use external programs to compare
279 The extdiff Mercurial extension allows you to use external programs to compare
280 revisions, or revision with working directory. The external diff programs are
280 revisions, or revision with working directory. The external diff programs are
281 called with a configurable set of options and two non-option arguments: paths
281 called with a configurable set of options and two non-option arguments: paths
282 to directories containing snapshots of files to compare.
282 to directories containing snapshots of files to compare.
283
283
284 The extdiff extension also allows you to configure new diff commands, so you
284 The extdiff extension also allows you to configure new diff commands, so you
285 do not need to type "hg extdiff -p kdiff3" always.
285 do not need to type "hg extdiff -p kdiff3" always.
286
286
287 [extdiff]
287 [extdiff]
288 # add new command that runs GNU diff(1) in 'context diff' mode
288 # add new command that runs GNU diff(1) in 'context diff' mode
289 cdiff = gdiff -Nprc5
289 cdiff = gdiff -Nprc5
290 ## or the old way:
290 ## or the old way:
291 #cmd.cdiff = gdiff
291 #cmd.cdiff = gdiff
292 #opts.cdiff = -Nprc5
292 #opts.cdiff = -Nprc5
293
293
294 # add new command called vdiff, runs kdiff3
294 # add new command called vdiff, runs kdiff3
295 vdiff = kdiff3
295 vdiff = kdiff3
296
296
297 # add new command called meld, runs meld (no need to name twice)
297 # add new command called meld, runs meld (no need to name twice)
298 meld =
298 meld =
299
299
300 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
300 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
301 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
301 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
302 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
302 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
303 # your .vimrc
303 # your .vimrc
304 vimdiff = gvim -f '+next' '+execute "DirDiff" argv(0) argv(1)'
304 vimdiff = gvim -f "+next" \
305 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
305
306
306 Tool arguments can include variables that are expanded at runtime:
307 Tool arguments can include variables that are expanded at runtime:
307
308
308 $parent1, $plabel1 - filename, descriptive label of first parent
309 $parent1, $plabel1 - filename, descriptive label of first parent
309 $child, $clabel - filename, descriptive label of child revision
310 $child, $clabel - filename, descriptive label of child revision
310 $parent2, $plabel2 - filename, descriptive label of second parent
311 $parent2, $plabel2 - filename, descriptive label of second parent
311 $root - repository root
312 $root - repository root
312 $parent is an alias for $parent1.
313 $parent is an alias for $parent1.
313
314
314 The extdiff extension will look in your [diff-tools] and [merge-tools]
315 The extdiff extension will look in your [diff-tools] and [merge-tools]
315 sections for diff tool arguments, when none are specified in [extdiff].
316 sections for diff tool arguments, when none are specified in [extdiff].
316
317
317 [extdiff]
318 [extdiff]
318 kdiff3 =
319 kdiff3 =
319
320
320 [diff-tools]
321 [diff-tools]
321 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
322 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
322
323
323 You can use -I/-X and list of file or directory names like normal "hg diff"
324 You can use -I/-X and list of file or directory names like normal "hg diff"
324 command. The extdiff extension makes snapshots of only needed files, so
325 command. The extdiff extension makes snapshots of only needed files, so
325 running the external diff program will actually be pretty fast (at least
326 running the external diff program will actually be pretty fast (at least
326 faster than having to compare the entire tree).
327 faster than having to compare the entire tree).
327
328
328 list of commands:
329 list of commands:
329
330
330 extdiff use external program to diff repository (or selected files)
331 extdiff use external program to diff repository (or selected files)
331
332
332 use "hg -v help extdiff" to show builtin aliases and global options
333 use "hg -v help extdiff" to show builtin aliases and global options
333
334
334 $ echo 'extdiff = !' >> $HGRCPATH
335 $ echo 'extdiff = !' >> $HGRCPATH
335
336
336 Test help topic with same name as extension
337 Test help topic with same name as extension
337
338
338 $ cat > multirevs.py <<EOF
339 $ cat > multirevs.py <<EOF
339 > from mercurial import commands
340 > from mercurial import commands
340 > """multirevs extension
341 > """multirevs extension
341 > Big multi-line module docstring."""
342 > Big multi-line module docstring."""
342 > def multirevs(ui, repo, arg, *args, **opts):
343 > def multirevs(ui, repo, arg, *args, **opts):
343 > """multirevs command"""
344 > """multirevs command"""
344 > pass
345 > pass
345 > cmdtable = {
346 > cmdtable = {
346 > "multirevs": (multirevs, [], 'ARG')
347 > "multirevs": (multirevs, [], 'ARG')
347 > }
348 > }
348 > commands.norepo += ' multirevs'
349 > commands.norepo += ' multirevs'
349 > EOF
350 > EOF
350 $ echo "multirevs = multirevs.py" >> $HGRCPATH
351 $ echo "multirevs = multirevs.py" >> $HGRCPATH
351
352
352 $ hg help multirevs
353 $ hg help multirevs
353 Specifying Multiple Revisions
354 Specifying Multiple Revisions
354
355
355 When Mercurial accepts more than one revision, they may be specified
356 When Mercurial accepts more than one revision, they may be specified
356 individually, or provided as a topologically continuous range, separated
357 individually, or provided as a topologically continuous range, separated
357 by the ":" character.
358 by the ":" character.
358
359
359 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
360 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
360 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
361 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
361 specified, it defaults to revision number 0. If END is not specified, it
362 specified, it defaults to revision number 0. If END is not specified, it
362 defaults to the tip. The range ":" thus means "all revisions".
363 defaults to the tip. The range ":" thus means "all revisions".
363
364
364 If BEGIN is greater than END, revisions are treated in reverse order.
365 If BEGIN is greater than END, revisions are treated in reverse order.
365
366
366 A range acts as a closed interval. This means that a range of 3:5 gives 3,
367 A range acts as a closed interval. This means that a range of 3:5 gives 3,
367 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
368 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
368
369
369 use "hg help -c multirevs" to see help for the multirevs command
370 use "hg help -c multirevs" to see help for the multirevs command
370
371
371 $ hg help -c multirevs
372 $ hg help -c multirevs
372 hg multirevs ARG
373 hg multirevs ARG
373
374
374 multirevs command
375 multirevs command
375
376
376 use "hg -v help multirevs" to show more info
377 use "hg -v help multirevs" to show more info
377
378
378 $ hg multirevs
379 $ hg multirevs
379 hg multirevs: invalid arguments
380 hg multirevs: invalid arguments
380 hg multirevs ARG
381 hg multirevs ARG
381
382
382 multirevs command
383 multirevs command
383
384
384 use "hg help multirevs" to show the full help text
385 use "hg help multirevs" to show the full help text
385 [255]
386 [255]
386
387
387 $ echo "multirevs = !" >> $HGRCPATH
388 $ echo "multirevs = !" >> $HGRCPATH
388
389
389 Issue811: Problem loading extensions twice (by site and by user)
390 Issue811: Problem loading extensions twice (by site and by user)
390
391
391 $ debugpath=`pwd`/debugissue811.py
392 $ debugpath=`pwd`/debugissue811.py
392 $ cat > debugissue811.py <<EOF
393 $ cat > debugissue811.py <<EOF
393 > '''show all loaded extensions
394 > '''show all loaded extensions
394 > '''
395 > '''
395 > from mercurial import extensions, commands
396 > from mercurial import extensions, commands
396 >
397 >
397 > def debugextensions(ui):
398 > def debugextensions(ui):
398 > "yet another debug command"
399 > "yet another debug command"
399 > ui.write("%s\n" % '\n'.join([x for x, y in extensions.extensions()]))
400 > ui.write("%s\n" % '\n'.join([x for x, y in extensions.extensions()]))
400 >
401 >
401 > cmdtable = {"debugextensions": (debugextensions, (), "hg debugextensions")}
402 > cmdtable = {"debugextensions": (debugextensions, (), "hg debugextensions")}
402 > commands.norepo += " debugextensions"
403 > commands.norepo += " debugextensions"
403 > EOF
404 > EOF
404 $ echo "debugissue811 = $debugpath" >> $HGRCPATH
405 $ echo "debugissue811 = $debugpath" >> $HGRCPATH
405 $ echo "mq=" >> $HGRCPATH
406 $ echo "mq=" >> $HGRCPATH
406 $ echo "hgext.mq=" >> $HGRCPATH
407 $ echo "hgext.mq=" >> $HGRCPATH
407 $ echo "hgext/mq=" >> $HGRCPATH
408 $ echo "hgext/mq=" >> $HGRCPATH
408
409
409 Show extensions:
410 Show extensions:
410
411
411 $ hg debugextensions
412 $ hg debugextensions
412 debugissue811
413 debugissue811
413 mq
414 mq
414
415
415 Disabled extension commands:
416 Disabled extension commands:
416
417
417 $ HGRCPATH=
418 $ HGRCPATH=
418 $ export HGRCPATH
419 $ export HGRCPATH
419 $ hg help email
420 $ hg help email
420 'email' is provided by the following extension:
421 'email' is provided by the following extension:
421
422
422 patchbomb command to send changesets as (a series of) patch emails
423 patchbomb command to send changesets as (a series of) patch emails
423
424
424 use "hg help extensions" for information on enabling extensions
425 use "hg help extensions" for information on enabling extensions
425 $ hg qdel
426 $ hg qdel
426 hg: unknown command 'qdel'
427 hg: unknown command 'qdel'
427 'qdelete' is provided by the following extension:
428 'qdelete' is provided by the following extension:
428
429
429 mq manage a stack of patches
430 mq manage a stack of patches
430
431
431 use "hg help extensions" for information on enabling extensions
432 use "hg help extensions" for information on enabling extensions
432 [255]
433 [255]
433 $ hg churn
434 $ hg churn
434 hg: unknown command 'churn'
435 hg: unknown command 'churn'
435 'churn' is provided by the following extension:
436 'churn' is provided by the following extension:
436
437
437 churn command to display statistics about repository history
438 churn command to display statistics about repository history
438
439
439 use "hg help extensions" for information on enabling extensions
440 use "hg help extensions" for information on enabling extensions
440 [255]
441 [255]
441
442
442 Disabled extensions:
443 Disabled extensions:
443
444
444 $ hg help churn
445 $ hg help churn
445 churn extension - command to display statistics about repository history
446 churn extension - command to display statistics about repository history
446
447
447 use "hg help extensions" for information on enabling extensions
448 use "hg help extensions" for information on enabling extensions
448 $ hg help patchbomb
449 $ hg help patchbomb
449 patchbomb extension - command to send changesets as (a series of) patch emails
450 patchbomb extension - command to send changesets as (a series of) patch emails
450
451
451 use "hg help extensions" for information on enabling extensions
452 use "hg help extensions" for information on enabling extensions
452
453
453 Broken disabled extension and command:
454 Broken disabled extension and command:
454
455
455 $ mkdir hgext
456 $ mkdir hgext
456 $ echo > hgext/__init__.py
457 $ echo > hgext/__init__.py
457 $ cat > hgext/broken.py <<EOF
458 $ cat > hgext/broken.py <<EOF
458 > "broken extension'
459 > "broken extension'
459 > EOF
460 > EOF
460 $ cat > path.py <<EOF
461 $ cat > path.py <<EOF
461 > import os, sys
462 > import os, sys
462 > sys.path.insert(0, os.environ['HGEXTPATH'])
463 > sys.path.insert(0, os.environ['HGEXTPATH'])
463 > EOF
464 > EOF
464 $ HGEXTPATH=`pwd`
465 $ HGEXTPATH=`pwd`
465 $ export HGEXTPATH
466 $ export HGEXTPATH
466
467
467 $ hg --config extensions.path=./path.py help broken
468 $ hg --config extensions.path=./path.py help broken
468 broken extension - (no help text available)
469 broken extension - (no help text available)
469
470
470 use "hg help extensions" for information on enabling extensions
471 use "hg help extensions" for information on enabling extensions
471
472
472 $ cat > hgext/forest.py <<EOF
473 $ cat > hgext/forest.py <<EOF
473 > cmdtable = None
474 > cmdtable = None
474 > EOF
475 > EOF
475 $ hg --config extensions.path=./path.py help foo > /dev/null
476 $ hg --config extensions.path=./path.py help foo > /dev/null
476 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
477 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
477 hg: unknown command 'foo'
478 hg: unknown command 'foo'
478 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
479 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
479 [255]
480 [255]
General Comments 0
You need to be logged in to leave comments. Login now