Show More
@@ -9,7 +9,6 b'' | |||||
9 | from __future__ import absolute_import |
|
9 | from __future__ import absolute_import | |
10 |
|
10 | |||
11 | import errno |
|
11 | import errno | |
12 | import functools |
|
|||
13 | import hashlib |
|
12 | import hashlib | |
14 | import os |
|
13 | import os | |
15 | import shutil |
|
14 | import shutil | |
@@ -164,8 +163,8 b' def _peerorrepo(ui, path, create=False, ' | |||||
164 | obj = _peerlookup(path).instance(ui, path, create, intents=intents) |
|
163 | obj = _peerlookup(path).instance(ui, path, create, intents=intents) | |
165 | ui = getattr(obj, "ui", ui) |
|
164 | ui = getattr(obj, "ui", ui) | |
166 | if ui.configbool('devel', 'debug.extensions'): |
|
165 | if ui.configbool('devel', 'debug.extensions'): | |
167 | log = functools.partial( |
|
166 | log = lambda msg, *values: ui.debug('debug.extensions: ', | |
168 |
|
|
167 | msg % values, label='debug.extensions') | |
169 | else: |
|
168 | else: | |
170 | log = lambda *a, **kw: None |
|
169 | log = lambda *a, **kw: None | |
171 | for f in presetupfuncs or []: |
|
170 | for f in presetupfuncs or []: | |
@@ -175,7 +174,9 b' def _peerorrepo(ui, path, create=False, ' | |||||
175 | log(' - running reposetup for %s\n' % (name,)) |
|
174 | log(' - running reposetup for %s\n' % (name,)) | |
176 | hook = getattr(module, 'reposetup', None) |
|
175 | hook = getattr(module, 'reposetup', None) | |
177 | if hook: |
|
176 | if hook: | |
178 | hook(ui, obj) |
|
177 | with util.timedcm('reposetup %r', name) as stats: | |
|
178 | hook(ui, obj) | |||
|
179 | log(' > reposetup for %r took %s\n', name, stats) | |||
179 | if not obj.local(): |
|
180 | if not obj.local(): | |
180 | for f in wirepeersetupfuncs: |
|
181 | for f in wirepeersetupfuncs: | |
181 | f(ui, obj) |
|
182 | f(ui, obj) |
This diff has been collapsed as it changes many lines, (1745 lines changed) Show them Hide them | |||||
@@ -40,1716 +40,51 b' Test basic extension support' | |||||
40 |
|
40 | |||
41 | $ echo '[extensions]' >> $HGRCPATH |
|
41 | $ echo '[extensions]' >> $HGRCPATH | |
42 | $ echo "foobar = $abspath" >> $HGRCPATH |
|
42 | $ echo "foobar = $abspath" >> $HGRCPATH | |
43 | $ hg foo |
|
43 | ||
|
44 | Test extension setup timings | |||
|
45 | ||||
|
46 | $ hg foo --traceback --config devel.debug.extensions=yes --debug 2>&1 | |||
|
47 | debug.extensions: loading extensions | |||
|
48 | debug.extensions: - processing 1 entries | |||
|
49 | debug.extensions: - loading extension: 'foobar' | |||
|
50 | debug.extensions: > 'foobar' extension loaded in * (glob) | |||
|
51 | debug.extensions: - validating extension tables: 'foobar' | |||
|
52 | debug.extensions: - invoking registered callbacks: 'foobar' | |||
|
53 | debug.extensions: > callbacks completed in * (glob) | |||
|
54 | debug.extensions: > loaded 1 extensions, total time * (glob) | |||
|
55 | debug.extensions: - loading configtable attributes | |||
|
56 | debug.extensions: - executing uisetup hooks | |||
|
57 | debug.extensions: - running uisetup for 'foobar' | |||
|
58 | uisetup called [debug] | |||
44 | uisetup called |
|
59 | uisetup called | |
45 | uisetup called [status] |
|
60 | uisetup called [status] | |
46 | reposetup called for a |
|
61 | debug.extensions: > uisetup for 'foobar' took * (glob) | |
47 | ui == repo.ui |
|
62 | debug.extensions: - executing extsetup hooks | |
48 | reposetup called for a (chg !) |
|
63 | debug.extensions: - running extsetup for 'foobar' | |
49 | ui == repo.ui (chg !) |
|
64 | debug.extensions: > extsetup for 'foobar' took * (glob) | |
50 | Foo |
|
65 | debug.extensions: - executing remaining aftercallbacks | |
51 | $ hg foo --quiet |
|
66 | debug.extensions: > remaining aftercallbacks completed in * (glob) | |
52 | uisetup called (no-chg !) |
|
67 | debug.extensions: - loading extension registration objects | |
53 | reposetup called for a (chg !) |
|
68 | debug.extensions: > extension registration object loading took * (glob) | |
54 | ui == repo.ui |
|
69 | debug.extensions: extension loading complete | |
55 | Foo |
|
70 | debug.extensions: loading additional extensions | |
56 | $ hg foo --debug |
|
71 | debug.extensions: - processing 1 entries | |
57 | uisetup called [debug] (no-chg !) |
|
72 | debug.extensions: > loaded 0 extensions, total time * (glob) | |
58 | uisetup called (no-chg !) |
|
73 | debug.extensions: - loading configtable attributes | |
59 | uisetup called [status] (no-chg !) |
|
74 | debug.extensions: - executing uisetup hooks | |
60 | reposetup called for a (chg !) |
|
75 | debug.extensions: - executing extsetup hooks | |
61 | ui == repo.ui |
|
76 | debug.extensions: - executing remaining aftercallbacks | |
62 | Foo |
|
77 | debug.extensions: > remaining aftercallbacks completed in * (glob) | |
63 |
|
78 | debug.extensions: - loading extension registration objects | ||
64 | $ cd .. |
|
79 | debug.extensions: > extension registration object loading took * (glob) | |
65 | $ hg clone a b |
|
80 | debug.extensions: extension loading complete | |
66 | uisetup called (no-chg !) |
|
81 | debug.extensions: - executing reposetup hooks | |
67 | uisetup called [status] (no-chg !) |
|
82 | debug.extensions: - running reposetup for foobar | |
68 | reposetup called for a |
|
|||
69 | ui == repo.ui |
|
|||
70 | reposetup called for b |
|
|||
71 | ui == repo.ui |
|
|||
72 | updating to branch default |
|
|||
73 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
|||
74 |
|
||||
75 | $ hg bar |
|
|||
76 | uisetup called (no-chg !) |
|
|||
77 | uisetup called [status] (no-chg !) |
|
|||
78 | Bar |
|
|||
79 | $ echo 'foobar = !' >> $HGRCPATH |
|
|||
80 |
|
||||
81 | module/__init__.py-style |
|
|||
82 |
|
||||
83 | $ echo "barfoo = $barfoopath" >> $HGRCPATH |
|
|||
84 | $ cd a |
|
|||
85 | $ hg foo |
|
|||
86 | uisetup called |
|
|||
87 | uisetup called [status] |
|
|||
88 | reposetup called for a |
|
83 | reposetup called for a | |
89 | ui == repo.ui |
|
84 | ui == repo.ui | |
90 | reposetup called for a (chg !) |
|
85 | debug.extensions: > reposetup for 'foobar' took * (glob) | |
91 | ui == repo.ui (chg !) |
|
|||
92 | Foo |
|
86 | Foo | |
93 | $ echo 'barfoo = !' >> $HGRCPATH |
|
|||
94 |
|
||||
95 | Check that extensions are loaded in phases: |
|
|||
96 |
|
||||
97 | $ cat > foo.py <<EOF |
|
|||
98 | > import os |
|
|||
99 | > name = os.path.basename(__file__).rsplit('.', 1)[0] |
|
|||
100 | > print("1) %s imported" % name) |
|
|||
101 | > def uisetup(ui): |
|
|||
102 | > print("2) %s uisetup" % name) |
|
|||
103 | > def extsetup(): |
|
|||
104 | > print("3) %s extsetup" % name) |
|
|||
105 | > def reposetup(ui, repo): |
|
|||
106 | > print("4) %s reposetup" % name) |
|
|||
107 | > |
|
|||
108 | > # custom predicate to check registration of functions at loading |
|
|||
109 | > from mercurial import ( |
|
|||
110 | > registrar, |
|
|||
111 | > smartset, |
|
|||
112 | > ) |
|
|||
113 | > revsetpredicate = registrar.revsetpredicate() |
|
|||
114 | > @revsetpredicate(name, safe=True) # safe=True for query via hgweb |
|
|||
115 | > def custompredicate(repo, subset, x): |
|
|||
116 | > return smartset.baseset([r for r in subset if r in {0}]) |
|
|||
117 | > EOF |
|
|||
118 |
|
||||
119 | $ cp foo.py bar.py |
|
|||
120 | $ echo 'foo = foo.py' >> $HGRCPATH |
|
|||
121 | $ echo 'bar = bar.py' >> $HGRCPATH |
|
|||
122 |
|
||||
123 | Check normal command's load order of extensions and registration of functions |
|
|||
124 |
|
||||
125 | $ hg log -r "foo() and bar()" -q |
|
|||
126 | 1) foo imported |
|
|||
127 | 1) bar imported |
|
|||
128 | 2) foo uisetup |
|
|||
129 | 2) bar uisetup |
|
|||
130 | 3) foo extsetup |
|
|||
131 | 3) bar extsetup |
|
|||
132 | 4) foo reposetup |
|
|||
133 | 4) bar reposetup |
|
|||
134 | 0:c24b9ac61126 |
|
|||
135 |
|
||||
136 | Check hgweb's load order of extensions and registration of functions |
|
|||
137 |
|
||||
138 | $ cat > hgweb.cgi <<EOF |
|
|||
139 | > #!$PYTHON |
|
|||
140 | > from mercurial import demandimport; demandimport.enable() |
|
|||
141 | > from mercurial.hgweb import hgweb |
|
|||
142 | > from mercurial.hgweb import wsgicgi |
|
|||
143 | > application = hgweb('.', 'test repo') |
|
|||
144 | > wsgicgi.launch(application) |
|
|||
145 | > EOF |
|
|||
146 | $ . "$TESTDIR/cgienv" |
|
|||
147 |
|
||||
148 | $ PATH_INFO='/' SCRIPT_NAME='' $PYTHON hgweb.cgi \ |
|
|||
149 | > | grep '^[0-9]) ' # ignores HTML output |
|
|||
150 | 1) foo imported |
|
|||
151 | 1) bar imported |
|
|||
152 | 2) foo uisetup |
|
|||
153 | 2) bar uisetup |
|
|||
154 | 3) foo extsetup |
|
|||
155 | 3) bar extsetup |
|
|||
156 | 4) foo reposetup |
|
|||
157 | 4) bar reposetup |
|
|||
158 |
|
||||
159 | (check that revset predicate foo() and bar() are available) |
|
|||
160 |
|
||||
161 | #if msys |
|
|||
162 | $ PATH_INFO='//shortlog' |
|
|||
163 | #else |
|
|||
164 | $ PATH_INFO='/shortlog' |
|
|||
165 | #endif |
|
|||
166 | $ export PATH_INFO |
|
|||
167 | $ SCRIPT_NAME='' QUERY_STRING='rev=foo() and bar()' $PYTHON hgweb.cgi \ |
|
|||
168 | > | grep '<a href="/rev/[0-9a-z]*">' |
|
|||
169 | <a href="/rev/c24b9ac61126">add file</a> |
|
|||
170 |
|
||||
171 | $ echo 'foo = !' >> $HGRCPATH |
|
|||
172 | $ echo 'bar = !' >> $HGRCPATH |
|
|||
173 |
|
||||
174 | Check "from __future__ import absolute_import" support for external libraries |
|
|||
175 |
|
||||
176 | #if windows |
|
|||
177 | $ PATHSEP=";" |
|
|||
178 | #else |
|
|||
179 | $ PATHSEP=":" |
|
|||
180 | #endif |
|
|||
181 | $ export PATHSEP |
|
|||
182 |
|
||||
183 | $ mkdir $TESTTMP/libroot |
|
|||
184 | $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py |
|
|||
185 | $ mkdir $TESTTMP/libroot/mod |
|
|||
186 | $ touch $TESTTMP/libroot/mod/__init__.py |
|
|||
187 | $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py |
|
|||
188 |
|
||||
189 | $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF |
|
|||
190 | > from __future__ import absolute_import |
|
|||
191 | > import ambig # should load "libroot/ambig.py" |
|
|||
192 | > s = ambig.s |
|
|||
193 | > EOF |
|
|||
194 | $ cat > loadabs.py <<EOF |
|
|||
195 | > import mod.ambigabs as ambigabs |
|
|||
196 | > def extsetup(): |
|
|||
197 | > print('ambigabs.s=%s' % ambigabs.s) |
|
|||
198 | > EOF |
|
|||
199 | $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root) |
|
|||
200 | ambigabs.s=libroot/ambig.py |
|
|||
201 | $TESTTMP/a |
|
|||
202 |
|
||||
203 | #if no-py3k |
|
|||
204 | $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF |
|
|||
205 | > import ambig # should load "libroot/mod/ambig.py" |
|
|||
206 | > s = ambig.s |
|
|||
207 | > EOF |
|
|||
208 | $ cat > loadrel.py <<EOF |
|
|||
209 | > import mod.ambigrel as ambigrel |
|
|||
210 | > def extsetup(): |
|
|||
211 | > print('ambigrel.s=%s' % ambigrel.s) |
|
|||
212 | > EOF |
|
|||
213 | $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root) |
|
|||
214 | ambigrel.s=libroot/mod/ambig.py |
|
|||
215 | $TESTTMP/a |
|
|||
216 | #endif |
|
|||
217 |
|
||||
218 | Check absolute/relative import of extension specific modules |
|
|||
219 |
|
||||
220 | $ mkdir $TESTTMP/extroot |
|
|||
221 | $ cat > $TESTTMP/extroot/bar.py <<EOF |
|
|||
222 | > s = 'this is extroot.bar' |
|
|||
223 | > EOF |
|
|||
224 | $ mkdir $TESTTMP/extroot/sub1 |
|
|||
225 | $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF |
|
|||
226 | > s = 'this is extroot.sub1.__init__' |
|
|||
227 | > EOF |
|
|||
228 | $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF |
|
|||
229 | > s = 'this is extroot.sub1.baz' |
|
|||
230 | > EOF |
|
|||
231 | $ cat > $TESTTMP/extroot/__init__.py <<EOF |
|
|||
232 | > s = 'this is extroot.__init__' |
|
|||
233 | > import foo |
|
|||
234 | > def extsetup(ui): |
|
|||
235 | > ui.write('(extroot) ', foo.func(), '\n') |
|
|||
236 | > ui.flush() |
|
|||
237 | > EOF |
|
|||
238 |
|
||||
239 | $ cat > $TESTTMP/extroot/foo.py <<EOF |
|
|||
240 | > # test absolute import |
|
|||
241 | > buf = [] |
|
|||
242 | > def func(): |
|
|||
243 | > # "not locals" case |
|
|||
244 | > import extroot.bar |
|
|||
245 | > buf.append('import extroot.bar in func(): %s' % extroot.bar.s) |
|
|||
246 | > return '\n(extroot) '.join(buf) |
|
|||
247 | > # "fromlist == ('*',)" case |
|
|||
248 | > from extroot.bar import * |
|
|||
249 | > buf.append('from extroot.bar import *: %s' % s) |
|
|||
250 | > # "not fromlist" and "if '.' in name" case |
|
|||
251 | > import extroot.sub1.baz |
|
|||
252 | > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s) |
|
|||
253 | > # "not fromlist" and NOT "if '.' in name" case |
|
|||
254 | > import extroot |
|
|||
255 | > buf.append('import extroot: %s' % extroot.s) |
|
|||
256 | > # NOT "not fromlist" and NOT "level != -1" case |
|
|||
257 | > from extroot.bar import s |
|
|||
258 | > buf.append('from extroot.bar import s: %s' % s) |
|
|||
259 | > EOF |
|
|||
260 | $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root) |
|
|||
261 | (extroot) from extroot.bar import *: this is extroot.bar |
|
|||
262 | (extroot) import extroot.sub1.baz: this is extroot.sub1.baz |
|
|||
263 | (extroot) import extroot: this is extroot.__init__ |
|
|||
264 | (extroot) from extroot.bar import s: this is extroot.bar |
|
|||
265 | (extroot) import extroot.bar in func(): this is extroot.bar |
|
|||
266 | $TESTTMP/a |
|
|||
267 |
|
||||
268 | #if no-py3k |
|
|||
269 | $ rm "$TESTTMP"/extroot/foo.* |
|
|||
270 | $ rm -Rf "$TESTTMP/extroot/__pycache__" |
|
|||
271 | $ cat > $TESTTMP/extroot/foo.py <<EOF |
|
|||
272 | > # test relative import |
|
|||
273 | > buf = [] |
|
|||
274 | > def func(): |
|
|||
275 | > # "not locals" case |
|
|||
276 | > import bar |
|
|||
277 | > buf.append('import bar in func(): %s' % bar.s) |
|
|||
278 | > return '\n(extroot) '.join(buf) |
|
|||
279 | > # "fromlist == ('*',)" case |
|
|||
280 | > from bar import * |
|
|||
281 | > buf.append('from bar import *: %s' % s) |
|
|||
282 | > # "not fromlist" and "if '.' in name" case |
|
|||
283 | > import sub1.baz |
|
|||
284 | > buf.append('import sub1.baz: %s' % sub1.baz.s) |
|
|||
285 | > # "not fromlist" and NOT "if '.' in name" case |
|
|||
286 | > import sub1 |
|
|||
287 | > buf.append('import sub1: %s' % sub1.s) |
|
|||
288 | > # NOT "not fromlist" and NOT "level != -1" case |
|
|||
289 | > from bar import s |
|
|||
290 | > buf.append('from bar import s: %s' % s) |
|
|||
291 | > EOF |
|
|||
292 | $ hg --config extensions.extroot=$TESTTMP/extroot root |
|
|||
293 | (extroot) from bar import *: this is extroot.bar |
|
|||
294 | (extroot) import sub1.baz: this is extroot.sub1.baz |
|
|||
295 | (extroot) import sub1: this is extroot.sub1.__init__ |
|
|||
296 | (extroot) from bar import s: this is extroot.bar |
|
|||
297 | (extroot) import bar in func(): this is extroot.bar |
|
|||
298 | $TESTTMP/a |
|
|||
299 | #endif |
|
|||
300 |
|
||||
301 | #if demandimport |
|
|||
302 |
|
||||
303 | Examine whether module loading is delayed until actual referring, even |
|
|||
304 | though module is imported with "absolute_import" feature. |
|
|||
305 |
|
||||
306 | Files below in each packages are used for described purpose: |
|
|||
307 |
|
||||
308 | - "called": examine whether "from MODULE import ATTR" works correctly |
|
|||
309 | - "unused": examine whether loading is delayed correctly |
|
|||
310 | - "used": examine whether "from PACKAGE import MODULE" works correctly |
|
|||
311 |
|
||||
312 | Package hierarchy is needed to examine whether demand importing works |
|
|||
313 | as expected for "from SUB.PACK.AGE import MODULE". |
|
|||
314 |
|
||||
315 | Setup "external library" to be imported with "absolute_import" |
|
|||
316 | feature. |
|
|||
317 |
|
||||
318 | $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2 |
|
|||
319 | $ touch $TESTTMP/extlibroot/__init__.py |
|
|||
320 | $ touch $TESTTMP/extlibroot/lsub1/__init__.py |
|
|||
321 | $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py |
|
|||
322 |
|
||||
323 | $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<EOF |
|
|||
324 | > def func(): |
|
|||
325 | > return "this is extlibroot.lsub1.lsub2.called.func()" |
|
|||
326 | > EOF |
|
|||
327 | $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<EOF |
|
|||
328 | > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally") |
|
|||
329 | > EOF |
|
|||
330 | $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<EOF |
|
|||
331 | > detail = "this is extlibroot.lsub1.lsub2.used" |
|
|||
332 | > EOF |
|
|||
333 |
|
||||
334 | Setup sub-package of "external library", which causes instantiation of |
|
|||
335 | demandmod in "recurse down the module chain" code path. Relative |
|
|||
336 | importing with "absolute_import" feature isn't tested, because "level |
|
|||
337 | >=1 " doesn't cause instantiation of demandmod. |
|
|||
338 |
|
||||
339 | $ mkdir -p $TESTTMP/extlibroot/recursedown/abs |
|
|||
340 | $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<EOF |
|
|||
341 | > detail = "this is extlibroot.recursedown.abs.used" |
|
|||
342 | > EOF |
|
|||
343 | $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<EOF |
|
|||
344 | > from __future__ import absolute_import |
|
|||
345 | > from extlibroot.recursedown.abs.used import detail |
|
|||
346 | > EOF |
|
|||
347 |
|
||||
348 | $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy |
|
|||
349 | $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<EOF |
|
|||
350 | > detail = "this is extlibroot.recursedown.legacy.used" |
|
|||
351 | > EOF |
|
|||
352 | $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<EOF |
|
|||
353 | > # legacy style (level == -1) import |
|
|||
354 | > from extlibroot.recursedown.legacy.used import detail |
|
|||
355 | > EOF |
|
|||
356 |
|
||||
357 | $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<EOF |
|
|||
358 | > from __future__ import absolute_import |
|
|||
359 | > from extlibroot.recursedown.abs import detail as absdetail |
|
|||
360 | > from .legacy import detail as legacydetail |
|
|||
361 | > EOF |
|
|||
362 |
|
||||
363 | Setup package that re-exports an attribute of its submodule as the same |
|
|||
364 | name. This leaves 'shadowing.used' pointing to 'used.detail', but still |
|
|||
365 | the submodule 'used' should be somehow accessible. (issue5617) |
|
|||
366 |
|
||||
367 | $ mkdir -p $TESTTMP/extlibroot/shadowing |
|
|||
368 | $ cat > $TESTTMP/extlibroot/shadowing/used.py <<EOF |
|
|||
369 | > detail = "this is extlibroot.shadowing.used" |
|
|||
370 | > EOF |
|
|||
371 | $ cat > $TESTTMP/extlibroot/shadowing/proxied.py <<EOF |
|
|||
372 | > from __future__ import absolute_import |
|
|||
373 | > from extlibroot.shadowing.used import detail |
|
|||
374 | > EOF |
|
|||
375 | $ cat > $TESTTMP/extlibroot/shadowing/__init__.py <<EOF |
|
|||
376 | > from __future__ import absolute_import |
|
|||
377 | > from .used import detail as used |
|
|||
378 | > EOF |
|
|||
379 |
|
||||
380 | Setup extension local modules to be imported with "absolute_import" |
|
|||
381 | feature. |
|
|||
382 |
|
||||
383 | $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2 |
|
|||
384 | $ touch $TESTTMP/absextroot/xsub1/__init__.py |
|
|||
385 | $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py |
|
|||
386 |
|
||||
387 | $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<EOF |
|
|||
388 | > def func(): |
|
|||
389 | > return "this is absextroot.xsub1.xsub2.called.func()" |
|
|||
390 | > EOF |
|
|||
391 | $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<EOF |
|
|||
392 | > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally") |
|
|||
393 | > EOF |
|
|||
394 | $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<EOF |
|
|||
395 | > detail = "this is absextroot.xsub1.xsub2.used" |
|
|||
396 | > EOF |
|
|||
397 |
|
||||
398 | Setup extension local modules to examine whether demand importing |
|
|||
399 | works as expected in "level > 1" case. |
|
|||
400 |
|
||||
401 | $ cat > $TESTTMP/absextroot/relimportee.py <<EOF |
|
|||
402 | > detail = "this is absextroot.relimportee" |
|
|||
403 | > EOF |
|
|||
404 | $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<EOF |
|
|||
405 | > from __future__ import absolute_import |
|
|||
406 | > from ... import relimportee |
|
|||
407 | > detail = "this relimporter imports %r" % (relimportee.detail) |
|
|||
408 | > EOF |
|
|||
409 |
|
||||
410 | Setup modules, which actually import extension local modules at |
|
|||
411 | runtime. |
|
|||
412 |
|
||||
413 | $ cat > $TESTTMP/absextroot/absolute.py << EOF |
|
|||
414 | > from __future__ import absolute_import |
|
|||
415 | > |
|
|||
416 | > # import extension local modules absolutely (level = 0) |
|
|||
417 | > from absextroot.xsub1.xsub2 import used, unused |
|
|||
418 | > from absextroot.xsub1.xsub2.called import func |
|
|||
419 | > |
|
|||
420 | > def getresult(): |
|
|||
421 | > result = [] |
|
|||
422 | > result.append(used.detail) |
|
|||
423 | > result.append(func()) |
|
|||
424 | > return result |
|
|||
425 | > EOF |
|
|||
426 |
|
||||
427 | $ cat > $TESTTMP/absextroot/relative.py << EOF |
|
|||
428 | > from __future__ import absolute_import |
|
|||
429 | > |
|
|||
430 | > # import extension local modules relatively (level == 1) |
|
|||
431 | > from .xsub1.xsub2 import used, unused |
|
|||
432 | > from .xsub1.xsub2.called import func |
|
|||
433 | > |
|
|||
434 | > # import a module, which implies "importing with level > 1" |
|
|||
435 | > from .xsub1.xsub2 import relimporter |
|
|||
436 | > |
|
|||
437 | > def getresult(): |
|
|||
438 | > result = [] |
|
|||
439 | > result.append(used.detail) |
|
|||
440 | > result.append(func()) |
|
|||
441 | > result.append(relimporter.detail) |
|
|||
442 | > return result |
|
|||
443 | > EOF |
|
|||
444 |
|
||||
445 | Setup main procedure of extension. |
|
|||
446 |
|
||||
447 | $ cat > $TESTTMP/absextroot/__init__.py <<EOF |
|
|||
448 | > from __future__ import absolute_import |
|
|||
449 | > from mercurial import registrar |
|
|||
450 | > cmdtable = {} |
|
|||
451 | > command = registrar.command(cmdtable) |
|
|||
452 | > |
|
|||
453 | > # "absolute" and "relative" shouldn't be imported before actual |
|
|||
454 | > # command execution, because (1) they import same modules, and (2) |
|
|||
455 | > # preceding import (= instantiate "demandmod" object instead of |
|
|||
456 | > # real "module" object) might hide problem of succeeding import. |
|
|||
457 | > |
|
|||
458 | > @command(b'showabsolute', [], norepo=True) |
|
|||
459 | > def showabsolute(ui, *args, **opts): |
|
|||
460 | > from absextroot import absolute |
|
|||
461 | > ui.write(b'ABS: %s\n' % '\nABS: '.join(absolute.getresult())) |
|
|||
462 | > |
|
|||
463 | > @command(b'showrelative', [], norepo=True) |
|
|||
464 | > def showrelative(ui, *args, **opts): |
|
|||
465 | > from . import relative |
|
|||
466 | > ui.write(b'REL: %s\n' % '\nREL: '.join(relative.getresult())) |
|
|||
467 | > |
|
|||
468 | > # import modules from external library |
|
|||
469 | > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused |
|
|||
470 | > from extlibroot.lsub1.lsub2.called import func as lfunc |
|
|||
471 | > from extlibroot.recursedown import absdetail, legacydetail |
|
|||
472 | > from extlibroot.shadowing import proxied |
|
|||
473 | > |
|
|||
474 | > def uisetup(ui): |
|
|||
475 | > result = [] |
|
|||
476 | > result.append(lused.detail) |
|
|||
477 | > result.append(lfunc()) |
|
|||
478 | > result.append(absdetail) |
|
|||
479 | > result.append(legacydetail) |
|
|||
480 | > result.append(proxied.detail) |
|
|||
481 | > ui.write(b'LIB: %s\n' % '\nLIB: '.join(result)) |
|
|||
482 | > EOF |
|
|||
483 |
|
||||
484 | Examine module importing. |
|
|||
485 |
|
||||
486 | $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute) |
|
|||
487 | LIB: this is extlibroot.lsub1.lsub2.used |
|
|||
488 | LIB: this is extlibroot.lsub1.lsub2.called.func() |
|
|||
489 | LIB: this is extlibroot.recursedown.abs.used |
|
|||
490 | LIB: this is extlibroot.recursedown.legacy.used |
|
|||
491 | LIB: this is extlibroot.shadowing.used |
|
|||
492 | ABS: this is absextroot.xsub1.xsub2.used |
|
|||
493 | ABS: this is absextroot.xsub1.xsub2.called.func() |
|
|||
494 |
|
||||
495 | $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative) |
|
|||
496 | LIB: this is extlibroot.lsub1.lsub2.used |
|
|||
497 | LIB: this is extlibroot.lsub1.lsub2.called.func() |
|
|||
498 | LIB: this is extlibroot.recursedown.abs.used |
|
|||
499 | LIB: this is extlibroot.recursedown.legacy.used |
|
|||
500 | LIB: this is extlibroot.shadowing.used |
|
|||
501 | REL: this is absextroot.xsub1.xsub2.used |
|
|||
502 | REL: this is absextroot.xsub1.xsub2.called.func() |
|
|||
503 | REL: this relimporter imports 'this is absextroot.relimportee' |
|
|||
504 |
|
||||
505 | Examine whether sub-module is imported relatively as expected. |
|
|||
506 |
|
||||
507 | See also issue5208 for detail about example case on Python 3.x. |
|
|||
508 |
|
||||
509 | $ f -q $TESTTMP/extlibroot/lsub1/lsub2/notexist.py |
|
|||
510 | $TESTTMP/extlibroot/lsub1/lsub2/notexist.py: file not found |
|
|||
511 |
|
||||
512 | $ cat > $TESTTMP/notexist.py <<EOF |
|
|||
513 | > text = 'notexist.py at root is loaded unintentionally\n' |
|
|||
514 | > EOF |
|
|||
515 |
|
||||
516 | $ cat > $TESTTMP/checkrelativity.py <<EOF |
|
|||
517 | > from mercurial import registrar |
|
|||
518 | > cmdtable = {} |
|
|||
519 | > command = registrar.command(cmdtable) |
|
|||
520 | > |
|
|||
521 | > # demand import avoids failure of importing notexist here |
|
|||
522 | > import extlibroot.lsub1.lsub2.notexist |
|
|||
523 | > |
|
|||
524 | > @command(b'checkrelativity', [], norepo=True) |
|
|||
525 | > def checkrelativity(ui, *args, **opts): |
|
|||
526 | > try: |
|
|||
527 | > ui.write(extlibroot.lsub1.lsub2.notexist.text) |
|
|||
528 | > return 1 # unintentional success |
|
|||
529 | > except ImportError: |
|
|||
530 | > pass # intentional failure |
|
|||
531 | > EOF |
|
|||
532 |
|
||||
533 | $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.checkrelativity=$TESTTMP/checkrelativity.py checkrelativity) |
|
|||
534 |
|
||||
535 | #endif |
|
|||
536 |
|
||||
537 | Make sure a broken uisetup doesn't globally break hg: |
|
|||
538 | $ cat > $TESTTMP/baduisetup.py <<EOF |
|
|||
539 | > def uisetup(ui): |
|
|||
540 | > 1/0 |
|
|||
541 | > EOF |
|
|||
542 |
|
||||
543 | Even though the extension fails during uisetup, hg is still basically usable: |
|
|||
544 | $ hg --config extensions.baduisetup=$TESTTMP/baduisetup.py version |
|
|||
545 | Traceback (most recent call last): |
|
|||
546 | File "*/mercurial/extensions.py", line *, in _runuisetup (glob) |
|
|||
547 | uisetup(ui) |
|
|||
548 | File "$TESTTMP/baduisetup.py", line 2, in uisetup |
|
|||
549 | 1/0 |
|
|||
550 | ZeroDivisionError: integer division or modulo by zero |
|
|||
551 | *** failed to set up extension baduisetup: integer division or modulo by zero |
|
|||
552 | Mercurial Distributed SCM (version *) (glob) |
|
|||
553 | (see https://mercurial-scm.org for more information) |
|
|||
554 |
|
||||
555 | Copyright (C) 2005-* Matt Mackall and others (glob) |
|
|||
556 | This is free software; see the source for copying conditions. There is NO |
|
|||
557 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
|||
558 |
|
87 | |||
559 |
$ |
|
88 | $ cd .. | |
560 |
|
89 | |||
561 | hide outer repo |
|
90 | $ echo 'foobar = !' >> $HGRCPATH | |
562 | $ hg init |
|
|||
563 |
|
||||
564 | $ cat > empty.py <<EOF |
|
|||
565 | > '''empty cmdtable |
|
|||
566 | > ''' |
|
|||
567 | > cmdtable = {} |
|
|||
568 | > EOF |
|
|||
569 | $ emptypath=`pwd`/empty.py |
|
|||
570 | $ echo "empty = $emptypath" >> $HGRCPATH |
|
|||
571 | $ hg help empty |
|
|||
572 | empty extension - empty cmdtable |
|
|||
573 |
|
||||
574 | no commands defined |
|
|||
575 |
|
||||
576 |
|
||||
577 | $ echo 'empty = !' >> $HGRCPATH |
|
|||
578 |
|
||||
579 | $ cat > debugextension.py <<EOF |
|
|||
580 | > '''only debugcommands |
|
|||
581 | > ''' |
|
|||
582 | > from mercurial import registrar |
|
|||
583 | > cmdtable = {} |
|
|||
584 | > command = registrar.command(cmdtable) |
|
|||
585 | > @command(b'debugfoobar', [], b'hg debugfoobar') |
|
|||
586 | > def debugfoobar(ui, repo, *args, **opts): |
|
|||
587 | > "yet another debug command" |
|
|||
588 | > pass |
|
|||
589 | > @command(b'foo', [], b'hg foo') |
|
|||
590 | > def foo(ui, repo, *args, **opts): |
|
|||
591 | > """yet another foo command |
|
|||
592 | > This command has been DEPRECATED since forever. |
|
|||
593 | > """ |
|
|||
594 | > pass |
|
|||
595 | > EOF |
|
|||
596 | $ debugpath=`pwd`/debugextension.py |
|
|||
597 | $ echo "debugextension = $debugpath" >> $HGRCPATH |
|
|||
598 |
|
||||
599 | $ hg help debugextension |
|
|||
600 | hg debugextensions |
|
|||
601 |
|
||||
602 | show information about active extensions |
|
|||
603 |
|
||||
604 | options: |
|
|||
605 |
|
||||
606 | (some details hidden, use --verbose to show complete help) |
|
|||
607 |
|
||||
608 |
|
||||
609 | $ hg --verbose help debugextension |
|
|||
610 | hg debugextensions |
|
|||
611 |
|
||||
612 | show information about active extensions |
|
|||
613 |
|
||||
614 | options: |
|
|||
615 |
|
||||
616 | -T --template TEMPLATE display with template (EXPERIMENTAL) |
|
|||
617 |
|
||||
618 | global options ([+] can be repeated): |
|
|||
619 |
|
||||
620 | -R --repository REPO repository root directory or name of overlay bundle |
|
|||
621 | file |
|
|||
622 | --cwd DIR change working directory |
|
|||
623 | -y --noninteractive do not prompt, automatically pick the first choice for |
|
|||
624 | all prompts |
|
|||
625 | -q --quiet suppress output |
|
|||
626 | -v --verbose enable additional output |
|
|||
627 | --color TYPE when to colorize (boolean, always, auto, never, or |
|
|||
628 | debug) |
|
|||
629 | --config CONFIG [+] set/override config option (use 'section.name=value') |
|
|||
630 | --debug enable debugging output |
|
|||
631 | --debugger start debugger |
|
|||
632 | --encoding ENCODE set the charset encoding (default: ascii) |
|
|||
633 | --encodingmode MODE set the charset encoding mode (default: strict) |
|
|||
634 | --traceback always print a traceback on exception |
|
|||
635 | --time time how long the command takes |
|
|||
636 | --profile print command execution profile |
|
|||
637 | --version output version information and exit |
|
|||
638 | -h --help display help and exit |
|
|||
639 | --hidden consider hidden changesets |
|
|||
640 | --pager TYPE when to paginate (boolean, always, auto, or never) |
|
|||
641 | (default: auto) |
|
|||
642 |
|
||||
643 |
|
||||
644 |
|
||||
645 |
|
||||
646 |
|
||||
647 |
|
||||
648 | $ hg --debug help debugextension |
|
|||
649 | hg debugextensions |
|
|||
650 |
|
||||
651 | show information about active extensions |
|
|||
652 |
|
||||
653 | options: |
|
|||
654 |
|
||||
655 | -T --template TEMPLATE display with template (EXPERIMENTAL) |
|
|||
656 |
|
||||
657 | global options ([+] can be repeated): |
|
|||
658 |
|
||||
659 | -R --repository REPO repository root directory or name of overlay bundle |
|
|||
660 | file |
|
|||
661 | --cwd DIR change working directory |
|
|||
662 | -y --noninteractive do not prompt, automatically pick the first choice for |
|
|||
663 | all prompts |
|
|||
664 | -q --quiet suppress output |
|
|||
665 | -v --verbose enable additional output |
|
|||
666 | --color TYPE when to colorize (boolean, always, auto, never, or |
|
|||
667 | debug) |
|
|||
668 | --config CONFIG [+] set/override config option (use 'section.name=value') |
|
|||
669 | --debug enable debugging output |
|
|||
670 | --debugger start debugger |
|
|||
671 | --encoding ENCODE set the charset encoding (default: ascii) |
|
|||
672 | --encodingmode MODE set the charset encoding mode (default: strict) |
|
|||
673 | --traceback always print a traceback on exception |
|
|||
674 | --time time how long the command takes |
|
|||
675 | --profile print command execution profile |
|
|||
676 | --version output version information and exit |
|
|||
677 | -h --help display help and exit |
|
|||
678 | --hidden consider hidden changesets |
|
|||
679 | --pager TYPE when to paginate (boolean, always, auto, or never) |
|
|||
680 | (default: auto) |
|
|||
681 |
|
||||
682 |
|
||||
683 |
|
||||
684 |
|
||||
685 |
|
||||
686 | $ echo 'debugextension = !' >> $HGRCPATH |
|
|||
687 |
|
||||
688 | Asking for help about a deprecated extension should do something useful: |
|
|||
689 |
|
||||
690 | $ hg help glog |
|
|||
691 | 'glog' is provided by the following extension: |
|
|||
692 |
|
||||
693 | graphlog command to view revision graphs from a shell (DEPRECATED) |
|
|||
694 |
|
||||
695 | (use 'hg help extensions' for information on enabling extensions) |
|
|||
696 |
|
||||
697 | Extension module help vs command help: |
|
|||
698 |
|
||||
699 | $ echo 'extdiff =' >> $HGRCPATH |
|
|||
700 | $ hg help extdiff |
|
|||
701 | hg extdiff [OPT]... [FILE]... |
|
|||
702 |
|
||||
703 | use external program to diff repository (or selected files) |
|
|||
704 |
|
||||
705 | Show differences between revisions for the specified files, using an |
|
|||
706 | external program. The default program used is diff, with default options |
|
|||
707 | "-Npru". |
|
|||
708 |
|
||||
709 | To select a different program, use the -p/--program option. The program |
|
|||
710 | will be passed the names of two directories to compare. To pass additional |
|
|||
711 | options to the program, use -o/--option. These will be passed before the |
|
|||
712 | names of the directories to compare. |
|
|||
713 |
|
||||
714 | When two revision arguments are given, then changes are shown between |
|
|||
715 | those revisions. If only one revision is specified then that revision is |
|
|||
716 | compared to the working directory, and, when no revisions are specified, |
|
|||
717 | the working directory files are compared to its parent. |
|
|||
718 |
|
||||
719 | (use 'hg help -e extdiff' to show help for the extdiff extension) |
|
|||
720 |
|
||||
721 | options ([+] can be repeated): |
|
|||
722 |
|
||||
723 | -p --program CMD comparison program to run |
|
|||
724 | -o --option OPT [+] pass option to comparison program |
|
|||
725 | -r --rev REV [+] revision |
|
|||
726 | -c --change REV change made by revision |
|
|||
727 | --patch compare patches for two revisions |
|
|||
728 | -I --include PATTERN [+] include names matching the given patterns |
|
|||
729 | -X --exclude PATTERN [+] exclude names matching the given patterns |
|
|||
730 | -S --subrepos recurse into subrepositories |
|
|||
731 |
|
||||
732 | (some details hidden, use --verbose to show complete help) |
|
|||
733 |
|
||||
734 |
|
||||
735 |
|
||||
736 |
|
||||
737 |
|
||||
738 |
|
||||
739 |
|
||||
740 |
|
||||
741 |
|
||||
742 |
|
||||
743 | $ hg help --extension extdiff |
|
|||
744 | extdiff extension - command to allow external programs to compare revisions |
|
|||
745 |
|
||||
746 | The extdiff Mercurial extension allows you to use external programs to compare |
|
|||
747 | revisions, or revision with working directory. The external diff programs are |
|
|||
748 | called with a configurable set of options and two non-option arguments: paths |
|
|||
749 | to directories containing snapshots of files to compare. |
|
|||
750 |
|
||||
751 | If there is more than one file being compared and the "child" revision is the |
|
|||
752 | working directory, any modifications made in the external diff program will be |
|
|||
753 | copied back to the working directory from the temporary directory. |
|
|||
754 |
|
||||
755 | The extdiff extension also allows you to configure new diff commands, so you |
|
|||
756 | do not need to type 'hg extdiff -p kdiff3' always. |
|
|||
757 |
|
||||
758 | [extdiff] |
|
|||
759 | # add new command that runs GNU diff(1) in 'context diff' mode |
|
|||
760 | cdiff = gdiff -Nprc5 |
|
|||
761 | ## or the old way: |
|
|||
762 | #cmd.cdiff = gdiff |
|
|||
763 | #opts.cdiff = -Nprc5 |
|
|||
764 |
|
||||
765 | # add new command called meld, runs meld (no need to name twice). If |
|
|||
766 | # the meld executable is not available, the meld tool in [merge-tools] |
|
|||
767 | # will be used, if available |
|
|||
768 | meld = |
|
|||
769 |
|
||||
770 | # add new command called vimdiff, runs gvimdiff with DirDiff plugin |
|
|||
771 | # (see http://www.vim.org/scripts/script.php?script_id=102) Non |
|
|||
772 | # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in |
|
|||
773 | # your .vimrc |
|
|||
774 | vimdiff = gvim -f "+next" \ |
|
|||
775 | "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))" |
|
|||
776 |
|
||||
777 | Tool arguments can include variables that are expanded at runtime: |
|
|||
778 |
|
||||
779 | $parent1, $plabel1 - filename, descriptive label of first parent |
|
|||
780 | $child, $clabel - filename, descriptive label of child revision |
|
|||
781 | $parent2, $plabel2 - filename, descriptive label of second parent |
|
|||
782 | $root - repository root |
|
|||
783 | $parent is an alias for $parent1. |
|
|||
784 |
|
||||
785 | The extdiff extension will look in your [diff-tools] and [merge-tools] |
|
|||
786 | sections for diff tool arguments, when none are specified in [extdiff]. |
|
|||
787 |
|
||||
788 | [extdiff] |
|
|||
789 | kdiff3 = |
|
|||
790 |
|
||||
791 | [diff-tools] |
|
|||
792 | kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child |
|
|||
793 |
|
||||
794 | You can use -I/-X and list of file or directory names like normal 'hg diff' |
|
|||
795 | command. The extdiff extension makes snapshots of only needed files, so |
|
|||
796 | running the external diff program will actually be pretty fast (at least |
|
|||
797 | faster than having to compare the entire tree). |
|
|||
798 |
|
||||
799 | list of commands: |
|
|||
800 |
|
||||
801 | extdiff use external program to diff repository (or selected files) |
|
|||
802 |
|
||||
803 | (use 'hg help -v -e extdiff' to show built-in aliases and global options) |
|
|||
804 |
|
||||
805 |
|
||||
806 |
|
||||
807 |
|
||||
808 |
|
||||
809 |
|
||||
810 |
|
||||
811 |
|
||||
812 |
|
||||
813 |
|
||||
814 |
|
||||
815 |
|
||||
816 |
|
||||
817 |
|
||||
818 |
|
||||
819 |
|
||||
820 | $ echo 'extdiff = !' >> $HGRCPATH |
|
|||
821 |
|
||||
822 | Test help topic with same name as extension |
|
|||
823 |
|
||||
824 | $ cat > multirevs.py <<EOF |
|
|||
825 | > from mercurial import commands, registrar |
|
|||
826 | > cmdtable = {} |
|
|||
827 | > command = registrar.command(cmdtable) |
|
|||
828 | > """multirevs extension |
|
|||
829 | > Big multi-line module docstring.""" |
|
|||
830 | > @command(b'multirevs', [], b'ARG', norepo=True) |
|
|||
831 | > def multirevs(ui, repo, arg, *args, **opts): |
|
|||
832 | > """multirevs command""" |
|
|||
833 | > pass |
|
|||
834 | > EOF |
|
|||
835 | $ echo "multirevs = multirevs.py" >> $HGRCPATH |
|
|||
836 |
|
||||
837 | $ hg help multirevs | tail |
|
|||
838 | used): |
|
|||
839 |
|
||||
840 | hg update :@ |
|
|||
841 |
|
||||
842 | - Show diff between tags 1.3 and 1.5 (this works because the first and the |
|
|||
843 | last revisions of the revset are used): |
|
|||
844 |
|
||||
845 | hg diff -r 1.3::1.5 |
|
|||
846 |
|
||||
847 | use 'hg help -c multirevs' to see help for the multirevs command |
|
|||
848 |
|
||||
849 |
|
||||
850 |
|
||||
851 |
|
||||
852 |
|
||||
853 |
|
||||
854 | $ hg help -c multirevs |
|
|||
855 | hg multirevs ARG |
|
|||
856 |
|
||||
857 | multirevs command |
|
|||
858 |
|
||||
859 | (some details hidden, use --verbose to show complete help) |
|
|||
860 |
|
||||
861 |
|
||||
862 |
|
||||
863 | $ hg multirevs |
|
|||
864 | hg multirevs: invalid arguments |
|
|||
865 | hg multirevs ARG |
|
|||
866 |
|
||||
867 | multirevs command |
|
|||
868 |
|
||||
869 | (use 'hg multirevs -h' to show more help) |
|
|||
870 | [255] |
|
|||
871 |
|
||||
872 |
|
||||
873 |
|
||||
874 | $ echo "multirevs = !" >> $HGRCPATH |
|
|||
875 |
|
||||
876 | Issue811: Problem loading extensions twice (by site and by user) |
|
|||
877 |
|
||||
878 | $ cat <<EOF >> $HGRCPATH |
|
|||
879 | > mq = |
|
|||
880 | > strip = |
|
|||
881 | > hgext.mq = |
|
|||
882 | > hgext/mq = |
|
|||
883 | > EOF |
|
|||
884 |
|
||||
885 | Show extensions: |
|
|||
886 | (note that mq force load strip, also checking it's not loaded twice) |
|
|||
887 |
|
||||
888 | #if no-extraextensions |
|
|||
889 | $ hg debugextensions |
|
|||
890 | mq |
|
|||
891 | strip |
|
|||
892 | #endif |
|
|||
893 |
|
||||
894 | For extensions, which name matches one of its commands, help |
|
|||
895 | message should ask '-v -e' to get list of built-in aliases |
|
|||
896 | along with extension help itself |
|
|||
897 |
|
||||
898 | $ mkdir $TESTTMP/d |
|
|||
899 | $ cat > $TESTTMP/d/dodo.py <<EOF |
|
|||
900 | > """ |
|
|||
901 | > This is an awesome 'dodo' extension. It does nothing and |
|
|||
902 | > writes 'Foo foo' |
|
|||
903 | > """ |
|
|||
904 | > from mercurial import commands, registrar |
|
|||
905 | > cmdtable = {} |
|
|||
906 | > command = registrar.command(cmdtable) |
|
|||
907 | > @command(b'dodo', [], b'hg dodo') |
|
|||
908 | > def dodo(ui, *args, **kwargs): |
|
|||
909 | > """Does nothing""" |
|
|||
910 | > ui.write(b"I do nothing. Yay\\n") |
|
|||
911 | > @command(b'foofoo', [], b'hg foofoo') |
|
|||
912 | > def foofoo(ui, *args, **kwargs): |
|
|||
913 | > """Writes 'Foo foo'""" |
|
|||
914 | > ui.write(b"Foo foo\\n") |
|
|||
915 | > EOF |
|
|||
916 | $ dodopath=$TESTTMP/d/dodo.py |
|
|||
917 |
|
||||
918 | $ echo "dodo = $dodopath" >> $HGRCPATH |
|
|||
919 |
|
||||
920 | Make sure that user is asked to enter '-v -e' to get list of built-in aliases |
|
|||
921 | $ hg help -e dodo |
|
|||
922 | dodo extension - |
|
|||
923 |
|
||||
924 | This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo' |
|
|||
925 |
|
||||
926 | list of commands: |
|
|||
927 |
|
||||
928 | dodo Does nothing |
|
|||
929 | foofoo Writes 'Foo foo' |
|
|||
930 |
|
||||
931 | (use 'hg help -v -e dodo' to show built-in aliases and global options) |
|
|||
932 |
|
||||
933 | Make sure that '-v -e' prints list of built-in aliases along with |
|
|||
934 | extension help itself |
|
|||
935 | $ hg help -v -e dodo |
|
|||
936 | dodo extension - |
|
|||
937 |
|
||||
938 | This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo' |
|
|||
939 |
|
||||
940 | list of commands: |
|
|||
941 |
|
||||
942 | dodo Does nothing |
|
|||
943 | foofoo Writes 'Foo foo' |
|
|||
944 |
|
||||
945 | global options ([+] can be repeated): |
|
|||
946 |
|
||||
947 | -R --repository REPO repository root directory or name of overlay bundle |
|
|||
948 | file |
|
|||
949 | --cwd DIR change working directory |
|
|||
950 | -y --noninteractive do not prompt, automatically pick the first choice for |
|
|||
951 | all prompts |
|
|||
952 | -q --quiet suppress output |
|
|||
953 | -v --verbose enable additional output |
|
|||
954 | --color TYPE when to colorize (boolean, always, auto, never, or |
|
|||
955 | debug) |
|
|||
956 | --config CONFIG [+] set/override config option (use 'section.name=value') |
|
|||
957 | --debug enable debugging output |
|
|||
958 | --debugger start debugger |
|
|||
959 | --encoding ENCODE set the charset encoding (default: ascii) |
|
|||
960 | --encodingmode MODE set the charset encoding mode (default: strict) |
|
|||
961 | --traceback always print a traceback on exception |
|
|||
962 | --time time how long the command takes |
|
|||
963 | --profile print command execution profile |
|
|||
964 | --version output version information and exit |
|
|||
965 | -h --help display help and exit |
|
|||
966 | --hidden consider hidden changesets |
|
|||
967 | --pager TYPE when to paginate (boolean, always, auto, or never) |
|
|||
968 | (default: auto) |
|
|||
969 |
|
||||
970 | Make sure that single '-v' option shows help and built-ins only for 'dodo' command |
|
|||
971 | $ hg help -v dodo |
|
|||
972 | hg dodo |
|
|||
973 |
|
||||
974 | Does nothing |
|
|||
975 |
|
||||
976 | (use 'hg help -e dodo' to show help for the dodo extension) |
|
|||
977 |
|
||||
978 | options: |
|
|||
979 |
|
||||
980 | --mq operate on patch repository |
|
|||
981 |
|
||||
982 | global options ([+] can be repeated): |
|
|||
983 |
|
||||
984 | -R --repository REPO repository root directory or name of overlay bundle |
|
|||
985 | file |
|
|||
986 | --cwd DIR change working directory |
|
|||
987 | -y --noninteractive do not prompt, automatically pick the first choice for |
|
|||
988 | all prompts |
|
|||
989 | -q --quiet suppress output |
|
|||
990 | -v --verbose enable additional output |
|
|||
991 | --color TYPE when to colorize (boolean, always, auto, never, or |
|
|||
992 | debug) |
|
|||
993 | --config CONFIG [+] set/override config option (use 'section.name=value') |
|
|||
994 | --debug enable debugging output |
|
|||
995 | --debugger start debugger |
|
|||
996 | --encoding ENCODE set the charset encoding (default: ascii) |
|
|||
997 | --encodingmode MODE set the charset encoding mode (default: strict) |
|
|||
998 | --traceback always print a traceback on exception |
|
|||
999 | --time time how long the command takes |
|
|||
1000 | --profile print command execution profile |
|
|||
1001 | --version output version information and exit |
|
|||
1002 | -h --help display help and exit |
|
|||
1003 | --hidden consider hidden changesets |
|
|||
1004 | --pager TYPE when to paginate (boolean, always, auto, or never) |
|
|||
1005 | (default: auto) |
|
|||
1006 |
|
||||
1007 | In case when extension name doesn't match any of its commands, |
|
|||
1008 | help message should ask for '-v' to get list of built-in aliases |
|
|||
1009 | along with extension help |
|
|||
1010 | $ cat > $TESTTMP/d/dudu.py <<EOF |
|
|||
1011 | > """ |
|
|||
1012 | > This is an awesome 'dudu' extension. It does something and |
|
|||
1013 | > also writes 'Beep beep' |
|
|||
1014 | > """ |
|
|||
1015 | > from mercurial import commands, registrar |
|
|||
1016 | > cmdtable = {} |
|
|||
1017 | > command = registrar.command(cmdtable) |
|
|||
1018 | > @command(b'something', [], b'hg something') |
|
|||
1019 | > def something(ui, *args, **kwargs): |
|
|||
1020 | > """Does something""" |
|
|||
1021 | > ui.write(b"I do something. Yaaay\\n") |
|
|||
1022 | > @command(b'beep', [], b'hg beep') |
|
|||
1023 | > def beep(ui, *args, **kwargs): |
|
|||
1024 | > """Writes 'Beep beep'""" |
|
|||
1025 | > ui.write(b"Beep beep\\n") |
|
|||
1026 | > EOF |
|
|||
1027 | $ dudupath=$TESTTMP/d/dudu.py |
|
|||
1028 |
|
||||
1029 | $ echo "dudu = $dudupath" >> $HGRCPATH |
|
|||
1030 |
|
||||
1031 | $ hg help -e dudu |
|
|||
1032 | dudu extension - |
|
|||
1033 |
|
||||
1034 | This is an awesome 'dudu' extension. It does something and also writes 'Beep |
|
|||
1035 | beep' |
|
|||
1036 |
|
||||
1037 | list of commands: |
|
|||
1038 |
|
||||
1039 | beep Writes 'Beep beep' |
|
|||
1040 | something Does something |
|
|||
1041 |
|
||||
1042 | (use 'hg help -v dudu' to show built-in aliases and global options) |
|
|||
1043 |
|
||||
1044 | In case when extension name doesn't match any of its commands, |
|
|||
1045 | help options '-v' and '-v -e' should be equivalent |
|
|||
1046 | $ hg help -v dudu |
|
|||
1047 | dudu extension - |
|
|||
1048 |
|
||||
1049 | This is an awesome 'dudu' extension. It does something and also writes 'Beep |
|
|||
1050 | beep' |
|
|||
1051 |
|
||||
1052 | list of commands: |
|
|||
1053 |
|
||||
1054 | beep Writes 'Beep beep' |
|
|||
1055 | something Does something |
|
|||
1056 |
|
||||
1057 | global options ([+] can be repeated): |
|
|||
1058 |
|
||||
1059 | -R --repository REPO repository root directory or name of overlay bundle |
|
|||
1060 | file |
|
|||
1061 | --cwd DIR change working directory |
|
|||
1062 | -y --noninteractive do not prompt, automatically pick the first choice for |
|
|||
1063 | all prompts |
|
|||
1064 | -q --quiet suppress output |
|
|||
1065 | -v --verbose enable additional output |
|
|||
1066 | --color TYPE when to colorize (boolean, always, auto, never, or |
|
|||
1067 | debug) |
|
|||
1068 | --config CONFIG [+] set/override config option (use 'section.name=value') |
|
|||
1069 | --debug enable debugging output |
|
|||
1070 | --debugger start debugger |
|
|||
1071 | --encoding ENCODE set the charset encoding (default: ascii) |
|
|||
1072 | --encodingmode MODE set the charset encoding mode (default: strict) |
|
|||
1073 | --traceback always print a traceback on exception |
|
|||
1074 | --time time how long the command takes |
|
|||
1075 | --profile print command execution profile |
|
|||
1076 | --version output version information and exit |
|
|||
1077 | -h --help display help and exit |
|
|||
1078 | --hidden consider hidden changesets |
|
|||
1079 | --pager TYPE when to paginate (boolean, always, auto, or never) |
|
|||
1080 | (default: auto) |
|
|||
1081 |
|
||||
1082 | $ hg help -v -e dudu |
|
|||
1083 | dudu extension - |
|
|||
1084 |
|
||||
1085 | This is an awesome 'dudu' extension. It does something and also writes 'Beep |
|
|||
1086 | beep' |
|
|||
1087 |
|
||||
1088 | list of commands: |
|
|||
1089 |
|
||||
1090 | beep Writes 'Beep beep' |
|
|||
1091 | something Does something |
|
|||
1092 |
|
||||
1093 | global options ([+] can be repeated): |
|
|||
1094 |
|
||||
1095 | -R --repository REPO repository root directory or name of overlay bundle |
|
|||
1096 | file |
|
|||
1097 | --cwd DIR change working directory |
|
|||
1098 | -y --noninteractive do not prompt, automatically pick the first choice for |
|
|||
1099 | all prompts |
|
|||
1100 | -q --quiet suppress output |
|
|||
1101 | -v --verbose enable additional output |
|
|||
1102 | --color TYPE when to colorize (boolean, always, auto, never, or |
|
|||
1103 | debug) |
|
|||
1104 | --config CONFIG [+] set/override config option (use 'section.name=value') |
|
|||
1105 | --debug enable debugging output |
|
|||
1106 | --debugger start debugger |
|
|||
1107 | --encoding ENCODE set the charset encoding (default: ascii) |
|
|||
1108 | --encodingmode MODE set the charset encoding mode (default: strict) |
|
|||
1109 | --traceback always print a traceback on exception |
|
|||
1110 | --time time how long the command takes |
|
|||
1111 | --profile print command execution profile |
|
|||
1112 | --version output version information and exit |
|
|||
1113 | -h --help display help and exit |
|
|||
1114 | --hidden consider hidden changesets |
|
|||
1115 | --pager TYPE when to paginate (boolean, always, auto, or never) |
|
|||
1116 | (default: auto) |
|
|||
1117 |
|
||||
1118 | Disabled extension commands: |
|
|||
1119 |
|
||||
1120 | $ ORGHGRCPATH=$HGRCPATH |
|
|||
1121 | $ HGRCPATH= |
|
|||
1122 | $ export HGRCPATH |
|
|||
1123 | $ hg help email |
|
|||
1124 | 'email' is provided by the following extension: |
|
|||
1125 |
|
||||
1126 | patchbomb command to send changesets as (a series of) patch emails |
|
|||
1127 |
|
||||
1128 | (use 'hg help extensions' for information on enabling extensions) |
|
|||
1129 |
|
||||
1130 |
|
||||
1131 | $ hg qdel |
|
|||
1132 | hg: unknown command 'qdel' |
|
|||
1133 | 'qdelete' is provided by the following extension: |
|
|||
1134 |
|
||||
1135 | mq manage a stack of patches |
|
|||
1136 |
|
||||
1137 | (use 'hg help extensions' for information on enabling extensions) |
|
|||
1138 | [255] |
|
|||
1139 |
|
||||
1140 |
|
||||
1141 | $ hg churn |
|
|||
1142 | hg: unknown command 'churn' |
|
|||
1143 | 'churn' is provided by the following extension: |
|
|||
1144 |
|
||||
1145 | churn command to display statistics about repository history |
|
|||
1146 |
|
||||
1147 | (use 'hg help extensions' for information on enabling extensions) |
|
|||
1148 | [255] |
|
|||
1149 |
|
||||
1150 |
|
||||
1151 |
|
||||
1152 | Disabled extensions: |
|
|||
1153 |
|
||||
1154 | $ hg help churn |
|
|||
1155 | churn extension - command to display statistics about repository history |
|
|||
1156 |
|
||||
1157 | (use 'hg help extensions' for information on enabling extensions) |
|
|||
1158 |
|
||||
1159 | $ hg help patchbomb |
|
|||
1160 | patchbomb extension - command to send changesets as (a series of) patch emails |
|
|||
1161 |
|
||||
1162 | The series is started off with a "[PATCH 0 of N]" introduction, which |
|
|||
1163 | describes the series as a whole. |
|
|||
1164 |
|
||||
1165 | Each patch email has a Subject line of "[PATCH M of N] ...", using the first |
|
|||
1166 | line of the changeset description as the subject text. The message contains |
|
|||
1167 | two or three body parts: |
|
|||
1168 |
|
||||
1169 | - The changeset description. |
|
|||
1170 | - [Optional] The result of running diffstat on the patch. |
|
|||
1171 | - The patch itself, as generated by 'hg export'. |
|
|||
1172 |
|
||||
1173 | Each message refers to the first in the series using the In-Reply-To and |
|
|||
1174 | References headers, so they will show up as a sequence in threaded mail and |
|
|||
1175 | news readers, and in mail archives. |
|
|||
1176 |
|
||||
1177 | To configure other defaults, add a section like this to your configuration |
|
|||
1178 | file: |
|
|||
1179 |
|
||||
1180 | [email] |
|
|||
1181 | from = My Name <my@email> |
|
|||
1182 | to = recipient1, recipient2, ... |
|
|||
1183 | cc = cc1, cc2, ... |
|
|||
1184 | bcc = bcc1, bcc2, ... |
|
|||
1185 | reply-to = address1, address2, ... |
|
|||
1186 |
|
||||
1187 | Use "[patchbomb]" as configuration section name if you need to override global |
|
|||
1188 | "[email]" address settings. |
|
|||
1189 |
|
||||
1190 | Then you can use the 'hg email' command to mail a series of changesets as a |
|
|||
1191 | patchbomb. |
|
|||
1192 |
|
||||
1193 | You can also either configure the method option in the email section to be a |
|
|||
1194 | sendmail compatible mailer or fill out the [smtp] section so that the |
|
|||
1195 | patchbomb extension can automatically send patchbombs directly from the |
|
|||
1196 | commandline. See the [email] and [smtp] sections in hgrc(5) for details. |
|
|||
1197 |
|
||||
1198 | By default, 'hg email' will prompt for a "To" or "CC" header if you do not |
|
|||
1199 | supply one via configuration or the command line. You can override this to |
|
|||
1200 | never prompt by configuring an empty value: |
|
|||
1201 |
|
||||
1202 | [email] |
|
|||
1203 | cc = |
|
|||
1204 |
|
||||
1205 | You can control the default inclusion of an introduction message with the |
|
|||
1206 | "patchbomb.intro" configuration option. The configuration is always |
|
|||
1207 | overwritten by command line flags like --intro and --desc: |
|
|||
1208 |
|
||||
1209 | [patchbomb] |
|
|||
1210 | intro=auto # include introduction message if more than 1 patch (default) |
|
|||
1211 | intro=never # never include an introduction message |
|
|||
1212 | intro=always # always include an introduction message |
|
|||
1213 |
|
||||
1214 | You can specify a template for flags to be added in subject prefixes. Flags |
|
|||
1215 | specified by --flag option are exported as "{flags}" keyword: |
|
|||
1216 |
|
||||
1217 | [patchbomb] |
|
|||
1218 | flagtemplate = "{separate(' ', |
|
|||
1219 | ifeq(branch, 'default', '', branch|upper), |
|
|||
1220 | flags)}" |
|
|||
1221 |
|
||||
1222 | You can set patchbomb to always ask for confirmation by setting |
|
|||
1223 | "patchbomb.confirm" to true. |
|
|||
1224 |
|
||||
1225 | (use 'hg help extensions' for information on enabling extensions) |
|
|||
1226 |
|
||||
1227 |
|
||||
1228 | Broken disabled extension and command: |
|
|||
1229 |
|
||||
1230 | $ mkdir hgext |
|
|||
1231 | $ echo > hgext/__init__.py |
|
|||
1232 | $ cat > hgext/broken.py <<EOF |
|
|||
1233 | > "broken extension' |
|
|||
1234 | > EOF |
|
|||
1235 | $ cat > path.py <<EOF |
|
|||
1236 | > import os, sys |
|
|||
1237 | > sys.path.insert(0, os.environ['HGEXTPATH']) |
|
|||
1238 | > EOF |
|
|||
1239 | $ HGEXTPATH=`pwd` |
|
|||
1240 | $ export HGEXTPATH |
|
|||
1241 |
|
||||
1242 | $ hg --config extensions.path=./path.py help broken |
|
|||
1243 | broken extension - (no help text available) |
|
|||
1244 |
|
||||
1245 | (use 'hg help extensions' for information on enabling extensions) |
|
|||
1246 |
|
||||
1247 |
|
||||
1248 | $ cat > hgext/forest.py <<EOF |
|
|||
1249 | > cmdtable = None |
|
|||
1250 | > @command() |
|
|||
1251 | > def f(): |
|
|||
1252 | > pass |
|
|||
1253 | > @command(123) |
|
|||
1254 | > def g(): |
|
|||
1255 | > pass |
|
|||
1256 | > EOF |
|
|||
1257 | $ hg --config extensions.path=./path.py help foo |
|
|||
1258 | abort: no such help topic: foo |
|
|||
1259 | (try 'hg help --keyword foo') |
|
|||
1260 | [255] |
|
|||
1261 |
|
||||
1262 | $ cat > throw.py <<EOF |
|
|||
1263 | > from mercurial import commands, registrar, util |
|
|||
1264 | > cmdtable = {} |
|
|||
1265 | > command = registrar.command(cmdtable) |
|
|||
1266 | > class Bogon(Exception): pass |
|
|||
1267 | > @command(b'throw', [], b'hg throw', norepo=True) |
|
|||
1268 | > def throw(ui, **opts): |
|
|||
1269 | > """throws an exception""" |
|
|||
1270 | > raise Bogon() |
|
|||
1271 | > EOF |
|
|||
1272 |
|
||||
1273 | No declared supported version, extension complains: |
|
|||
1274 | $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*' |
|
|||
1275 | ** Unknown exception encountered with possibly-broken third-party extension throw |
|
|||
1276 | ** which supports versions unknown of Mercurial. |
|
|||
1277 | ** Please disable throw and try your action again. |
|
|||
1278 | ** If that fixes the bug please report it to the extension author. |
|
|||
1279 | ** Python * (glob) |
|
|||
1280 | ** Mercurial Distributed SCM * (glob) |
|
|||
1281 | ** Extensions loaded: throw |
|
|||
1282 |
|
||||
1283 | empty declaration of supported version, extension complains: |
|
|||
1284 | $ echo "testedwith = ''" >> throw.py |
|
|||
1285 | $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*' |
|
|||
1286 | ** Unknown exception encountered with possibly-broken third-party extension throw |
|
|||
1287 | ** which supports versions unknown of Mercurial. |
|
|||
1288 | ** Please disable throw and try your action again. |
|
|||
1289 | ** If that fixes the bug please report it to the extension author. |
|
|||
1290 | ** Python * (glob) |
|
|||
1291 | ** Mercurial Distributed SCM (*) (glob) |
|
|||
1292 | ** Extensions loaded: throw |
|
|||
1293 |
|
||||
1294 | If the extension specifies a buglink, show that: |
|
|||
1295 | $ echo 'buglink = "http://example.com/bts"' >> throw.py |
|
|||
1296 | $ rm -f throw.pyc throw.pyo |
|
|||
1297 | $ rm -Rf __pycache__ |
|
|||
1298 | $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*' |
|
|||
1299 | ** Unknown exception encountered with possibly-broken third-party extension throw |
|
|||
1300 | ** which supports versions unknown of Mercurial. |
|
|||
1301 | ** Please disable throw and try your action again. |
|
|||
1302 | ** If that fixes the bug please report it to http://example.com/bts |
|
|||
1303 | ** Python * (glob) |
|
|||
1304 | ** Mercurial Distributed SCM (*) (glob) |
|
|||
1305 | ** Extensions loaded: throw |
|
|||
1306 |
|
||||
1307 | If the extensions declare outdated versions, accuse the older extension first: |
|
|||
1308 | $ echo "from mercurial import util" >> older.py |
|
|||
1309 | $ echo "util.version = lambda:b'2.2'" >> older.py |
|
|||
1310 | $ echo "testedwith = b'1.9.3'" >> older.py |
|
|||
1311 | $ echo "testedwith = b'2.1.1'" >> throw.py |
|
|||
1312 | $ rm -f throw.pyc throw.pyo |
|
|||
1313 | $ rm -Rf __pycache__ |
|
|||
1314 | $ hg --config extensions.throw=throw.py --config extensions.older=older.py \ |
|
|||
1315 | > throw 2>&1 | egrep '^\*\*' |
|
|||
1316 | ** Unknown exception encountered with possibly-broken third-party extension older |
|
|||
1317 | ** which supports versions 1.9 of Mercurial. |
|
|||
1318 | ** Please disable older and try your action again. |
|
|||
1319 | ** If that fixes the bug please report it to the extension author. |
|
|||
1320 | ** Python * (glob) |
|
|||
1321 | ** Mercurial Distributed SCM (version 2.2) |
|
|||
1322 | ** Extensions loaded: throw, older |
|
|||
1323 |
|
||||
1324 | One extension only tested with older, one only with newer versions: |
|
|||
1325 | $ echo "util.version = lambda:b'2.1'" >> older.py |
|
|||
1326 | $ rm -f older.pyc older.pyo |
|
|||
1327 | $ rm -Rf __pycache__ |
|
|||
1328 | $ hg --config extensions.throw=throw.py --config extensions.older=older.py \ |
|
|||
1329 | > throw 2>&1 | egrep '^\*\*' |
|
|||
1330 | ** Unknown exception encountered with possibly-broken third-party extension older |
|
|||
1331 | ** which supports versions 1.9 of Mercurial. |
|
|||
1332 | ** Please disable older and try your action again. |
|
|||
1333 | ** If that fixes the bug please report it to the extension author. |
|
|||
1334 | ** Python * (glob) |
|
|||
1335 | ** Mercurial Distributed SCM (version 2.1) |
|
|||
1336 | ** Extensions loaded: throw, older |
|
|||
1337 |
|
||||
1338 | Older extension is tested with current version, the other only with newer: |
|
|||
1339 | $ echo "util.version = lambda:b'1.9.3'" >> older.py |
|
|||
1340 | $ rm -f older.pyc older.pyo |
|
|||
1341 | $ rm -Rf __pycache__ |
|
|||
1342 | $ hg --config extensions.throw=throw.py --config extensions.older=older.py \ |
|
|||
1343 | > throw 2>&1 | egrep '^\*\*' |
|
|||
1344 | ** Unknown exception encountered with possibly-broken third-party extension throw |
|
|||
1345 | ** which supports versions 2.1 of Mercurial. |
|
|||
1346 | ** Please disable throw and try your action again. |
|
|||
1347 | ** If that fixes the bug please report it to http://example.com/bts |
|
|||
1348 | ** Python * (glob) |
|
|||
1349 | ** Mercurial Distributed SCM (version 1.9.3) |
|
|||
1350 | ** Extensions loaded: throw, older |
|
|||
1351 |
|
||||
1352 | Ability to point to a different point |
|
|||
1353 | $ hg --config extensions.throw=throw.py --config extensions.older=older.py \ |
|
|||
1354 | > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*' |
|
|||
1355 | ** unknown exception encountered, please report by visiting |
|
|||
1356 | ** Your Local Goat Lenders |
|
|||
1357 | ** Python * (glob) |
|
|||
1358 | ** Mercurial Distributed SCM (*) (glob) |
|
|||
1359 | ** Extensions loaded: throw, older |
|
|||
1360 |
|
||||
1361 | Declare the version as supporting this hg version, show regular bts link: |
|
|||
1362 | $ hgver=`hg debuginstall -T '{hgver}'` |
|
|||
1363 | $ echo 'testedwith = """'"$hgver"'"""' >> throw.py |
|
|||
1364 | $ if [ -z "$hgver" ]; then |
|
|||
1365 | > echo "unable to fetch a mercurial version. Make sure __version__ is correct"; |
|
|||
1366 | > fi |
|
|||
1367 | $ rm -f throw.pyc throw.pyo |
|
|||
1368 | $ rm -Rf __pycache__ |
|
|||
1369 | $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*' |
|
|||
1370 | ** unknown exception encountered, please report by visiting |
|
|||
1371 | ** https://mercurial-scm.org/wiki/BugTracker |
|
|||
1372 | ** Python * (glob) |
|
|||
1373 | ** Mercurial Distributed SCM (*) (glob) |
|
|||
1374 | ** Extensions loaded: throw |
|
|||
1375 |
|
||||
1376 | Patch version is ignored during compatibility check |
|
|||
1377 | $ echo "testedwith = b'3.2'" >> throw.py |
|
|||
1378 | $ echo "util.version = lambda:b'3.2.2'" >> throw.py |
|
|||
1379 | $ rm -f throw.pyc throw.pyo |
|
|||
1380 | $ rm -Rf __pycache__ |
|
|||
1381 | $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*' |
|
|||
1382 | ** unknown exception encountered, please report by visiting |
|
|||
1383 | ** https://mercurial-scm.org/wiki/BugTracker |
|
|||
1384 | ** Python * (glob) |
|
|||
1385 | ** Mercurial Distributed SCM (*) (glob) |
|
|||
1386 | ** Extensions loaded: throw |
|
|||
1387 |
|
||||
1388 | Test version number support in 'hg version': |
|
|||
1389 | $ echo '__version__ = (1, 2, 3)' >> throw.py |
|
|||
1390 | $ rm -f throw.pyc throw.pyo |
|
|||
1391 | $ rm -Rf __pycache__ |
|
|||
1392 | $ hg version -v |
|
|||
1393 | Mercurial Distributed SCM (version *) (glob) |
|
|||
1394 | (see https://mercurial-scm.org for more information) |
|
|||
1395 |
|
||||
1396 | Copyright (C) 2005-* Matt Mackall and others (glob) |
|
|||
1397 | This is free software; see the source for copying conditions. There is NO |
|
|||
1398 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
|||
1399 |
|
||||
1400 | Enabled extensions: |
|
|||
1401 |
|
||||
1402 |
|
||||
1403 | $ hg version -v --config extensions.throw=throw.py |
|
|||
1404 | Mercurial Distributed SCM (version *) (glob) |
|
|||
1405 | (see https://mercurial-scm.org for more information) |
|
|||
1406 |
|
||||
1407 | Copyright (C) 2005-* Matt Mackall and others (glob) |
|
|||
1408 | This is free software; see the source for copying conditions. There is NO |
|
|||
1409 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
|||
1410 |
|
||||
1411 | Enabled extensions: |
|
|||
1412 |
|
||||
1413 | throw external 1.2.3 |
|
|||
1414 | $ echo 'getversion = lambda: b"1.twentythree"' >> throw.py |
|
|||
1415 | $ rm -f throw.pyc throw.pyo |
|
|||
1416 | $ rm -Rf __pycache__ |
|
|||
1417 | $ hg version -v --config extensions.throw=throw.py --config extensions.strip= |
|
|||
1418 | Mercurial Distributed SCM (version *) (glob) |
|
|||
1419 | (see https://mercurial-scm.org for more information) |
|
|||
1420 |
|
||||
1421 | Copyright (C) 2005-* Matt Mackall and others (glob) |
|
|||
1422 | This is free software; see the source for copying conditions. There is NO |
|
|||
1423 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
|||
1424 |
|
||||
1425 | Enabled extensions: |
|
|||
1426 |
|
||||
1427 | throw external 1.twentythree |
|
|||
1428 | strip internal |
|
|||
1429 |
|
||||
1430 | $ hg version -q --config extensions.throw=throw.py |
|
|||
1431 | Mercurial Distributed SCM (version *) (glob) |
|
|||
1432 |
|
||||
1433 | Test template output: |
|
|||
1434 |
|
||||
1435 | $ hg version --config extensions.strip= -T'{extensions}' |
|
|||
1436 | strip |
|
|||
1437 |
|
||||
1438 | Test JSON output of version: |
|
|||
1439 |
|
||||
1440 | $ hg version -Tjson |
|
|||
1441 | [ |
|
|||
1442 | { |
|
|||
1443 | "extensions": [], |
|
|||
1444 | "ver": "*" (glob) |
|
|||
1445 | } |
|
|||
1446 | ] |
|
|||
1447 |
|
||||
1448 | $ hg version --config extensions.throw=throw.py -Tjson |
|
|||
1449 | [ |
|
|||
1450 | { |
|
|||
1451 | "extensions": [{"bundled": false, "name": "throw", "ver": "1.twentythree"}], |
|
|||
1452 | "ver": "3.2.2" |
|
|||
1453 | } |
|
|||
1454 | ] |
|
|||
1455 |
|
||||
1456 | $ hg version --config extensions.strip= -Tjson |
|
|||
1457 | [ |
|
|||
1458 | { |
|
|||
1459 | "extensions": [{"bundled": true, "name": "strip", "ver": null}], |
|
|||
1460 | "ver": "*" (glob) |
|
|||
1461 | } |
|
|||
1462 | ] |
|
|||
1463 |
|
||||
1464 | Test template output of version: |
|
|||
1465 |
|
||||
1466 | $ hg version --config extensions.throw=throw.py --config extensions.strip= \ |
|
|||
1467 | > -T'{extensions % "{name} {pad(ver, 16)} ({if(bundled, "internal", "external")})\n"}' |
|
|||
1468 | throw 1.twentythree (external) |
|
|||
1469 | strip (internal) |
|
|||
1470 |
|
||||
1471 | Refuse to load extensions with minimum version requirements |
|
|||
1472 |
|
||||
1473 | $ cat > minversion1.py << EOF |
|
|||
1474 | > from mercurial import util |
|
|||
1475 | > util.version = lambda: b'3.5.2' |
|
|||
1476 | > minimumhgversion = b'3.6' |
|
|||
1477 | > EOF |
|
|||
1478 | $ hg --config extensions.minversion=minversion1.py version |
|
|||
1479 | (third party extension minversion requires version 3.6 or newer of Mercurial; disabling) |
|
|||
1480 | Mercurial Distributed SCM (version 3.5.2) |
|
|||
1481 | (see https://mercurial-scm.org for more information) |
|
|||
1482 |
|
||||
1483 | Copyright (C) 2005-* Matt Mackall and others (glob) |
|
|||
1484 | This is free software; see the source for copying conditions. There is NO |
|
|||
1485 | warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|
|||
1486 |
|
||||
1487 | $ cat > minversion2.py << EOF |
|
|||
1488 | > from mercurial import util |
|
|||
1489 | > util.version = lambda: b'3.6' |
|
|||
1490 | > minimumhgversion = b'3.7' |
|
|||
1491 | > EOF |
|
|||
1492 | $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third' |
|
|||
1493 | (third party extension minversion requires version 3.7 or newer of Mercurial; disabling) |
|
|||
1494 |
|
||||
1495 | Can load version that is only off by point release |
|
|||
1496 |
|
||||
1497 | $ cat > minversion2.py << EOF |
|
|||
1498 | > from mercurial import util |
|
|||
1499 | > util.version = lambda: b'3.6.1' |
|
|||
1500 | > minimumhgversion = b'3.6' |
|
|||
1501 | > EOF |
|
|||
1502 | $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third' |
|
|||
1503 | [1] |
|
|||
1504 |
|
||||
1505 | Can load minimum version identical to current |
|
|||
1506 |
|
||||
1507 | $ cat > minversion3.py << EOF |
|
|||
1508 | > from mercurial import util |
|
|||
1509 | > util.version = lambda: b'3.5' |
|
|||
1510 | > minimumhgversion = b'3.5' |
|
|||
1511 | > EOF |
|
|||
1512 | $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third' |
|
|||
1513 | [1] |
|
|||
1514 |
|
||||
1515 | Restore HGRCPATH |
|
|||
1516 |
|
||||
1517 | $ HGRCPATH=$ORGHGRCPATH |
|
|||
1518 | $ export HGRCPATH |
|
|||
1519 |
|
||||
1520 | Commands handling multiple repositories at a time should invoke only |
|
|||
1521 | "reposetup()" of extensions enabling in the target repository. |
|
|||
1522 |
|
||||
1523 | $ mkdir reposetup-test |
|
|||
1524 | $ cd reposetup-test |
|
|||
1525 |
|
||||
1526 | $ cat > $TESTTMP/reposetuptest.py <<EOF |
|
|||
1527 | > from mercurial import extensions |
|
|||
1528 | > def reposetup(ui, repo): |
|
|||
1529 | > ui.write(b'reposetup() for %s\n' % (repo.root)) |
|
|||
1530 | > ui.flush() |
|
|||
1531 | > EOF |
|
|||
1532 | $ hg init src |
|
|||
1533 | $ echo a > src/a |
|
|||
1534 | $ hg -R src commit -Am '#0 at src/a' |
|
|||
1535 | adding a |
|
|||
1536 | $ echo '[extensions]' >> src/.hg/hgrc |
|
|||
1537 | $ echo '# enable extension locally' >> src/.hg/hgrc |
|
|||
1538 | $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc |
|
|||
1539 | $ hg -R src status |
|
|||
1540 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1541 | reposetup() for $TESTTMP/reposetup-test/src (chg !) |
|
|||
1542 |
|
||||
1543 | #if no-extraextensions |
|
|||
1544 | $ hg --cwd src debugextensions |
|
|||
1545 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1546 | dodo (untested!) |
|
|||
1547 | dudu (untested!) |
|
|||
1548 | mq |
|
|||
1549 | reposetuptest (untested!) |
|
|||
1550 | strip |
|
|||
1551 | #endif |
|
|||
1552 |
|
||||
1553 | $ hg clone -U src clone-dst1 |
|
|||
1554 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1555 | $ hg init push-dst1 |
|
|||
1556 | $ hg -q -R src push push-dst1 |
|
|||
1557 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1558 | $ hg init pull-src1 |
|
|||
1559 | $ hg -q -R pull-src1 pull src |
|
|||
1560 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1561 |
|
||||
1562 | $ cat <<EOF >> $HGRCPATH |
|
|||
1563 | > [extensions] |
|
|||
1564 | > # disable extension globally and explicitly |
|
|||
1565 | > reposetuptest = ! |
|
|||
1566 | > EOF |
|
|||
1567 | $ hg clone -U src clone-dst2 |
|
|||
1568 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1569 | $ hg init push-dst2 |
|
|||
1570 | $ hg -q -R src push push-dst2 |
|
|||
1571 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1572 | $ hg init pull-src2 |
|
|||
1573 | $ hg -q -R pull-src2 pull src |
|
|||
1574 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1575 |
|
||||
1576 | $ cat <<EOF >> $HGRCPATH |
|
|||
1577 | > [extensions] |
|
|||
1578 | > # enable extension globally |
|
|||
1579 | > reposetuptest = $TESTTMP/reposetuptest.py |
|
|||
1580 | > EOF |
|
|||
1581 | $ hg clone -U src clone-dst3 |
|
|||
1582 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1583 | reposetup() for $TESTTMP/reposetup-test/clone-dst3 |
|
|||
1584 | $ hg init push-dst3 |
|
|||
1585 | reposetup() for $TESTTMP/reposetup-test/push-dst3 |
|
|||
1586 | $ hg -q -R src push push-dst3 |
|
|||
1587 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1588 | reposetup() for $TESTTMP/reposetup-test/push-dst3 |
|
|||
1589 | $ hg init pull-src3 |
|
|||
1590 | reposetup() for $TESTTMP/reposetup-test/pull-src3 |
|
|||
1591 | $ hg -q -R pull-src3 pull src |
|
|||
1592 | reposetup() for $TESTTMP/reposetup-test/pull-src3 |
|
|||
1593 | reposetup() for $TESTTMP/reposetup-test/src |
|
|||
1594 |
|
||||
1595 | $ echo '[extensions]' >> src/.hg/hgrc |
|
|||
1596 | $ echo '# disable extension locally' >> src/.hg/hgrc |
|
|||
1597 | $ echo 'reposetuptest = !' >> src/.hg/hgrc |
|
|||
1598 | $ hg clone -U src clone-dst4 |
|
|||
1599 | reposetup() for $TESTTMP/reposetup-test/clone-dst4 |
|
|||
1600 | $ hg init push-dst4 |
|
|||
1601 | reposetup() for $TESTTMP/reposetup-test/push-dst4 |
|
|||
1602 | $ hg -q -R src push push-dst4 |
|
|||
1603 | reposetup() for $TESTTMP/reposetup-test/push-dst4 |
|
|||
1604 | $ hg init pull-src4 |
|
|||
1605 | reposetup() for $TESTTMP/reposetup-test/pull-src4 |
|
|||
1606 | $ hg -q -R pull-src4 pull src |
|
|||
1607 | reposetup() for $TESTTMP/reposetup-test/pull-src4 |
|
|||
1608 |
|
||||
1609 | disabling in command line overlays with all configuration |
|
|||
1610 | $ hg --config extensions.reposetuptest=! clone -U src clone-dst5 |
|
|||
1611 | $ hg --config extensions.reposetuptest=! init push-dst5 |
|
|||
1612 | $ hg --config extensions.reposetuptest=! -q -R src push push-dst5 |
|
|||
1613 | $ hg --config extensions.reposetuptest=! init pull-src5 |
|
|||
1614 | $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src |
|
|||
1615 |
|
||||
1616 | $ cat <<EOF >> $HGRCPATH |
|
|||
1617 | > [extensions] |
|
|||
1618 | > # disable extension globally and explicitly |
|
|||
1619 | > reposetuptest = ! |
|
|||
1620 | > EOF |
|
|||
1621 | $ hg init parent |
|
|||
1622 | $ hg init parent/sub1 |
|
|||
1623 | $ echo 1 > parent/sub1/1 |
|
|||
1624 | $ hg -R parent/sub1 commit -Am '#0 at parent/sub1' |
|
|||
1625 | adding 1 |
|
|||
1626 | $ hg init parent/sub2 |
|
|||
1627 | $ hg init parent/sub2/sub21 |
|
|||
1628 | $ echo 21 > parent/sub2/sub21/21 |
|
|||
1629 | $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21' |
|
|||
1630 | adding 21 |
|
|||
1631 | $ cat > parent/sub2/.hgsub <<EOF |
|
|||
1632 | > sub21 = sub21 |
|
|||
1633 | > EOF |
|
|||
1634 | $ hg -R parent/sub2 commit -Am '#0 at parent/sub2' |
|
|||
1635 | adding .hgsub |
|
|||
1636 | $ hg init parent/sub3 |
|
|||
1637 | $ echo 3 > parent/sub3/3 |
|
|||
1638 | $ hg -R parent/sub3 commit -Am '#0 at parent/sub3' |
|
|||
1639 | adding 3 |
|
|||
1640 | $ cat > parent/.hgsub <<EOF |
|
|||
1641 | > sub1 = sub1 |
|
|||
1642 | > sub2 = sub2 |
|
|||
1643 | > sub3 = sub3 |
|
|||
1644 | > EOF |
|
|||
1645 | $ hg -R parent commit -Am '#0 at parent' |
|
|||
1646 | adding .hgsub |
|
|||
1647 | $ echo '[extensions]' >> parent/.hg/hgrc |
|
|||
1648 | $ echo '# enable extension locally' >> parent/.hg/hgrc |
|
|||
1649 | $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc |
|
|||
1650 | $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc |
|
|||
1651 | $ hg -R parent status -S -A |
|
|||
1652 | reposetup() for $TESTTMP/reposetup-test/parent |
|
|||
1653 | reposetup() for $TESTTMP/reposetup-test/parent/sub2 |
|
|||
1654 | C .hgsub |
|
|||
1655 | C .hgsubstate |
|
|||
1656 | C sub1/1 |
|
|||
1657 | C sub2/.hgsub |
|
|||
1658 | C sub2/.hgsubstate |
|
|||
1659 | C sub2/sub21/21 |
|
|||
1660 | C sub3/3 |
|
|||
1661 |
|
||||
1662 | $ cd .. |
|
|||
1663 |
|
||||
1664 | Prohibit registration of commands that don't use @command (issue5137) |
|
|||
1665 |
|
||||
1666 | $ hg init deprecated |
|
|||
1667 | $ cd deprecated |
|
|||
1668 |
|
||||
1669 | $ cat <<EOF > deprecatedcmd.py |
|
|||
1670 | > def deprecatedcmd(repo, ui): |
|
|||
1671 | > pass |
|
|||
1672 | > cmdtable = { |
|
|||
1673 | > b'deprecatedcmd': (deprecatedcmd, [], b''), |
|
|||
1674 | > } |
|
|||
1675 | > EOF |
|
|||
1676 | $ cat <<EOF > .hg/hgrc |
|
|||
1677 | > [extensions] |
|
|||
1678 | > deprecatedcmd = `pwd`/deprecatedcmd.py |
|
|||
1679 | > mq = ! |
|
|||
1680 | > hgext.mq = ! |
|
|||
1681 | > hgext/mq = ! |
|
|||
1682 | > EOF |
|
|||
1683 |
|
||||
1684 | $ hg deprecatedcmd > /dev/null |
|
|||
1685 | *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo |
|
|||
1686 | *** (use @command decorator to register 'deprecatedcmd') |
|
|||
1687 | hg: unknown command 'deprecatedcmd' |
|
|||
1688 | (use 'hg help' for a list of commands) |
|
|||
1689 | [255] |
|
|||
1690 |
|
||||
1691 | the extension shouldn't be loaded at all so the mq works: |
|
|||
1692 |
|
||||
1693 | $ hg qseries --config extensions.mq= > /dev/null |
|
|||
1694 | *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo |
|
|||
1695 | *** (use @command decorator to register 'deprecatedcmd') |
|
|||
1696 |
|
||||
1697 | $ cd .. |
|
|||
1698 |
|
||||
1699 | Test synopsis and docstring extending |
|
|||
1700 |
|
||||
1701 | $ hg init exthelp |
|
|||
1702 | $ cat > exthelp.py <<EOF |
|
|||
1703 | > from mercurial import commands, extensions |
|
|||
1704 | > def exbookmarks(orig, *args, **opts): |
|
|||
1705 | > return orig(*args, **opts) |
|
|||
1706 | > def uisetup(ui): |
|
|||
1707 | > synopsis = b' GREPME [--foo] [-x]' |
|
|||
1708 | > docstring = ''' |
|
|||
1709 | > GREPME make sure that this is in the help! |
|
|||
1710 | > ''' |
|
|||
1711 | > extensions.wrapcommand(commands.table, b'bookmarks', exbookmarks, |
|
|||
1712 | > synopsis, docstring) |
|
|||
1713 | > EOF |
|
|||
1714 | $ abspath=`pwd`/exthelp.py |
|
|||
1715 | $ echo '[extensions]' >> $HGRCPATH |
|
|||
1716 | $ echo "exthelp = $abspath" >> $HGRCPATH |
|
|||
1717 | $ cd exthelp |
|
|||
1718 | $ hg help bookmarks | grep GREPME |
|
|||
1719 | hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x] |
|
|||
1720 | GREPME make sure that this is in the help! |
|
|||
1721 | $ cd .. |
|
|||
1722 |
|
||||
1723 | Show deprecation warning for the use of cmdutil.command |
|
|||
1724 |
|
||||
1725 | $ cat > nonregistrar.py <<EOF |
|
|||
1726 | > from mercurial import cmdutil |
|
|||
1727 | > cmdtable = {} |
|
|||
1728 | > command = cmdutil.command(cmdtable) |
|
|||
1729 | > @command(b'foo', [], norepo=True) |
|
|||
1730 | > def foo(ui): |
|
|||
1731 | > pass |
|
|||
1732 | > EOF |
|
|||
1733 |
|
||||
1734 | Prohibit the use of unicode strings as the default value of options |
|
|||
1735 |
|
||||
1736 | $ hg init $TESTTMP/opt-unicode-default |
|
|||
1737 |
|
||||
1738 | $ cat > $TESTTMP/test_unicode_default_value.py << EOF |
|
|||
1739 | > from mercurial import registrar |
|
|||
1740 | > cmdtable = {} |
|
|||
1741 | > command = registrar.command(cmdtable) |
|
|||
1742 | > @command(b'dummy', [(b'', b'opt', u'value', u'help')], 'ext [OPTIONS]') |
|
|||
1743 | > def ext(*args, **opts): |
|
|||
1744 | > print(opts[b'opt']) |
|
|||
1745 | > EOF |
|
|||
1746 | $ cat > $TESTTMP/opt-unicode-default/.hg/hgrc << EOF |
|
|||
1747 | > [extensions] |
|
|||
1748 | > test_unicode_default_value = $TESTTMP/test_unicode_default_value.py |
|
|||
1749 | > EOF |
|
|||
1750 | $ hg -R $TESTTMP/opt-unicode-default dummy |
|
|||
1751 | *** failed to import extension test_unicode_default_value from $TESTTMP/test_unicode_default_value.py: unicode u'value' found in cmdtable.dummy |
|
|||
1752 | *** (use b'' to make it byte string) |
|
|||
1753 | hg: unknown command 'dummy' |
|
|||
1754 | (did you mean summary?) |
|
|||
1755 | [255] |
|
General Comments 0
You need to be logged in to leave comments.
Login now