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