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