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