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