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