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