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