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