##// END OF EJS Templates
demandimport: import sub-module relatively as expected (issue5208)...
FUJIWARA Katsunori -
r29736:14f077f7 default
parent child Browse files
Show More
@@ -1,308 +1,309 b''
1 # demandimport.py - global demand-loading of modules for Mercurial
1 # demandimport.py - global demand-loading of modules for Mercurial
2 #
2 #
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006, 2007 Matt Mackall <mpm@selenic.com>
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 demandimport - automatic demandloading of modules
9 demandimport - automatic demandloading of modules
10
10
11 To enable this module, do:
11 To enable this module, do:
12
12
13 import demandimport; demandimport.enable()
13 import demandimport; demandimport.enable()
14
14
15 Imports of the following forms will be demand-loaded:
15 Imports of the following forms will be demand-loaded:
16
16
17 import a, b.c
17 import a, b.c
18 import a.b as c
18 import a.b as c
19 from a import b,c # a will be loaded immediately
19 from a import b,c # a will be loaded immediately
20
20
21 These imports will not be delayed:
21 These imports will not be delayed:
22
22
23 from a import *
23 from a import *
24 b = __import__(a)
24 b = __import__(a)
25 '''
25 '''
26
26
27 from __future__ import absolute_import
27 from __future__ import absolute_import
28
28
29 import contextlib
29 import contextlib
30 import os
30 import os
31 import sys
31 import sys
32
32
33 # __builtin__ in Python 2, builtins in Python 3.
33 # __builtin__ in Python 2, builtins in Python 3.
34 try:
34 try:
35 import __builtin__ as builtins
35 import __builtin__ as builtins
36 except ImportError:
36 except ImportError:
37 import builtins
37 import builtins
38
38
39 contextmanager = contextlib.contextmanager
39 contextmanager = contextlib.contextmanager
40
40
41 _origimport = __import__
41 _origimport = __import__
42
42
43 nothing = object()
43 nothing = object()
44
44
45 # Python 3 doesn't have relative imports nor level -1.
45 # Python 3 doesn't have relative imports nor level -1.
46 level = -1
46 level = -1
47 if sys.version_info[0] >= 3:
47 if sys.version_info[0] >= 3:
48 level = 0
48 level = 0
49 _import = _origimport
49 _import = _origimport
50
50
51 def _hgextimport(importfunc, name, globals, *args, **kwargs):
51 def _hgextimport(importfunc, name, globals, *args, **kwargs):
52 try:
52 try:
53 return importfunc(name, globals, *args, **kwargs)
53 return importfunc(name, globals, *args, **kwargs)
54 except ImportError:
54 except ImportError:
55 if not globals:
55 if not globals:
56 raise
56 raise
57 # extensions are loaded with "hgext_" prefix
57 # extensions are loaded with "hgext_" prefix
58 hgextname = 'hgext_%s' % name
58 hgextname = 'hgext_%s' % name
59 nameroot = hgextname.split('.', 1)[0]
59 nameroot = hgextname.split('.', 1)[0]
60 contextroot = globals.get('__name__', '').split('.', 1)[0]
60 contextroot = globals.get('__name__', '').split('.', 1)[0]
61 if nameroot != contextroot:
61 if nameroot != contextroot:
62 raise
62 raise
63 # retry to import with "hgext_" prefix
63 # retry to import with "hgext_" prefix
64 return importfunc(hgextname, globals, *args, **kwargs)
64 return importfunc(hgextname, globals, *args, **kwargs)
65
65
66 class _demandmod(object):
66 class _demandmod(object):
67 """module demand-loader and proxy"""
67 """module demand-loader and proxy"""
68 def __init__(self, name, globals, locals, level=level):
68 def __init__(self, name, globals, locals, level=level):
69 if '.' in name:
69 if '.' in name:
70 head, rest = name.split('.', 1)
70 head, rest = name.split('.', 1)
71 after = [rest]
71 after = [rest]
72 else:
72 else:
73 head = name
73 head = name
74 after = []
74 after = []
75 object.__setattr__(self, "_data",
75 object.__setattr__(self, "_data",
76 (head, globals, locals, after, level, set()))
76 (head, globals, locals, after, level, set()))
77 object.__setattr__(self, "_module", None)
77 object.__setattr__(self, "_module", None)
78 def _extend(self, name):
78 def _extend(self, name):
79 """add to the list of submodules to load"""
79 """add to the list of submodules to load"""
80 self._data[3].append(name)
80 self._data[3].append(name)
81
81
82 def _addref(self, name):
82 def _addref(self, name):
83 """Record that the named module ``name`` imports this module.
83 """Record that the named module ``name`` imports this module.
84
84
85 References to this proxy class having the name of this module will be
85 References to this proxy class having the name of this module will be
86 replaced at module load time. We assume the symbol inside the importing
86 replaced at module load time. We assume the symbol inside the importing
87 module is identical to the "head" name of this module. We don't
87 module is identical to the "head" name of this module. We don't
88 actually know if "as X" syntax is being used to change the symbol name
88 actually know if "as X" syntax is being used to change the symbol name
89 because this information isn't exposed to __import__.
89 because this information isn't exposed to __import__.
90 """
90 """
91 self._data[5].add(name)
91 self._data[5].add(name)
92
92
93 def _load(self):
93 def _load(self):
94 if not self._module:
94 if not self._module:
95 head, globals, locals, after, level, modrefs = self._data
95 head, globals, locals, after, level, modrefs = self._data
96 mod = _hgextimport(_import, head, globals, locals, None, level)
96 mod = _hgextimport(_import, head, globals, locals, None, level)
97 if mod is self:
97 if mod is self:
98 # In this case, _hgextimport() above should imply
98 # In this case, _hgextimport() above should imply
99 # _demandimport(). Otherwise, _hgextimport() never
99 # _demandimport(). Otherwise, _hgextimport() never
100 # returns _demandmod. This isn't intentional behavior,
100 # returns _demandmod. This isn't intentional behavior,
101 # in fact. (see also issue5304 for detail)
101 # in fact. (see also issue5304 for detail)
102 #
102 #
103 # If self._module is already bound at this point, self
103 # If self._module is already bound at this point, self
104 # should be already _load()-ed while _hgextimport().
104 # should be already _load()-ed while _hgextimport().
105 # Otherwise, there is no way to import actual module
105 # Otherwise, there is no way to import actual module
106 # as expected, because (re-)invoking _hgextimport()
106 # as expected, because (re-)invoking _hgextimport()
107 # should cause same result.
107 # should cause same result.
108 # This is reason why _load() returns without any more
108 # This is reason why _load() returns without any more
109 # setup but assumes self to be already bound.
109 # setup but assumes self to be already bound.
110 mod = self._module
110 mod = self._module
111 assert mod and mod is not self, "%s, %s" % (self, mod)
111 assert mod and mod is not self, "%s, %s" % (self, mod)
112 return
112 return
113
113
114 # load submodules
114 # load submodules
115 def subload(mod, p):
115 def subload(mod, p):
116 h, t = p, None
116 h, t = p, None
117 if '.' in p:
117 if '.' in p:
118 h, t = p.split('.', 1)
118 h, t = p.split('.', 1)
119 if getattr(mod, h, nothing) is nothing:
119 if getattr(mod, h, nothing) is nothing:
120 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__))
120 setattr(mod, h, _demandmod(p, mod.__dict__, mod.__dict__,
121 level=1))
121 elif t:
122 elif t:
122 subload(getattr(mod, h), t)
123 subload(getattr(mod, h), t)
123
124
124 for x in after:
125 for x in after:
125 subload(mod, x)
126 subload(mod, x)
126
127
127 # Replace references to this proxy instance with the actual module.
128 # Replace references to this proxy instance with the actual module.
128 if locals and locals.get(head) == self:
129 if locals and locals.get(head) == self:
129 locals[head] = mod
130 locals[head] = mod
130
131
131 for modname in modrefs:
132 for modname in modrefs:
132 modref = sys.modules.get(modname, None)
133 modref = sys.modules.get(modname, None)
133 if modref and getattr(modref, head, None) == self:
134 if modref and getattr(modref, head, None) == self:
134 setattr(modref, head, mod)
135 setattr(modref, head, mod)
135
136
136 object.__setattr__(self, "_module", mod)
137 object.__setattr__(self, "_module", mod)
137
138
138 def __repr__(self):
139 def __repr__(self):
139 if self._module:
140 if self._module:
140 return "<proxied module '%s'>" % self._data[0]
141 return "<proxied module '%s'>" % self._data[0]
141 return "<unloaded module '%s'>" % self._data[0]
142 return "<unloaded module '%s'>" % self._data[0]
142 def __call__(self, *args, **kwargs):
143 def __call__(self, *args, **kwargs):
143 raise TypeError("%s object is not callable" % repr(self))
144 raise TypeError("%s object is not callable" % repr(self))
144 def __getattribute__(self, attr):
145 def __getattribute__(self, attr):
145 if attr in ('_data', '_extend', '_load', '_module', '_addref'):
146 if attr in ('_data', '_extend', '_load', '_module', '_addref'):
146 return object.__getattribute__(self, attr)
147 return object.__getattribute__(self, attr)
147 self._load()
148 self._load()
148 return getattr(self._module, attr)
149 return getattr(self._module, attr)
149 def __setattr__(self, attr, val):
150 def __setattr__(self, attr, val):
150 self._load()
151 self._load()
151 setattr(self._module, attr, val)
152 setattr(self._module, attr, val)
152
153
153 _pypy = '__pypy__' in sys.builtin_module_names
154 _pypy = '__pypy__' in sys.builtin_module_names
154
155
155 def _demandimport(name, globals=None, locals=None, fromlist=None, level=level):
156 def _demandimport(name, globals=None, locals=None, fromlist=None, level=level):
156 if not locals or name in ignore or fromlist == ('*',):
157 if not locals or name in ignore or fromlist == ('*',):
157 # these cases we can't really delay
158 # these cases we can't really delay
158 return _hgextimport(_import, name, globals, locals, fromlist, level)
159 return _hgextimport(_import, name, globals, locals, fromlist, level)
159 elif not fromlist:
160 elif not fromlist:
160 # import a [as b]
161 # import a [as b]
161 if '.' in name: # a.b
162 if '.' in name: # a.b
162 base, rest = name.split('.', 1)
163 base, rest = name.split('.', 1)
163 # email.__init__ loading email.mime
164 # email.__init__ loading email.mime
164 if globals and globals.get('__name__', None) == base:
165 if globals and globals.get('__name__', None) == base:
165 return _import(name, globals, locals, fromlist, level)
166 return _import(name, globals, locals, fromlist, level)
166 # if a is already demand-loaded, add b to its submodule list
167 # if a is already demand-loaded, add b to its submodule list
167 if base in locals:
168 if base in locals:
168 if isinstance(locals[base], _demandmod):
169 if isinstance(locals[base], _demandmod):
169 locals[base]._extend(rest)
170 locals[base]._extend(rest)
170 return locals[base]
171 return locals[base]
171 return _demandmod(name, globals, locals, level)
172 return _demandmod(name, globals, locals, level)
172 else:
173 else:
173 # There is a fromlist.
174 # There is a fromlist.
174 # from a import b,c,d
175 # from a import b,c,d
175 # from . import b,c,d
176 # from . import b,c,d
176 # from .a import b,c,d
177 # from .a import b,c,d
177
178
178 # level == -1: relative and absolute attempted (Python 2 only).
179 # level == -1: relative and absolute attempted (Python 2 only).
179 # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
180 # level >= 0: absolute only (Python 2 w/ absolute_import and Python 3).
180 # The modern Mercurial convention is to use absolute_import everywhere,
181 # The modern Mercurial convention is to use absolute_import everywhere,
181 # so modern Mercurial code will have level >= 0.
182 # so modern Mercurial code will have level >= 0.
182
183
183 # The name of the module the import statement is located in.
184 # The name of the module the import statement is located in.
184 globalname = globals.get('__name__')
185 globalname = globals.get('__name__')
185
186
186 def processfromitem(mod, attr):
187 def processfromitem(mod, attr):
187 """Process an imported symbol in the import statement.
188 """Process an imported symbol in the import statement.
188
189
189 If the symbol doesn't exist in the parent module, it must be a
190 If the symbol doesn't exist in the parent module, it must be a
190 module. We set missing modules up as _demandmod instances.
191 module. We set missing modules up as _demandmod instances.
191 """
192 """
192 symbol = getattr(mod, attr, nothing)
193 symbol = getattr(mod, attr, nothing)
193 if symbol is nothing:
194 if symbol is nothing:
194 mn = '%s.%s' % (mod.__name__, attr)
195 mn = '%s.%s' % (mod.__name__, attr)
195 if mn in ignore:
196 if mn in ignore:
196 importfunc = _origimport
197 importfunc = _origimport
197 else:
198 else:
198 importfunc = _demandmod
199 importfunc = _demandmod
199 symbol = importfunc(attr, mod.__dict__, locals, level=1)
200 symbol = importfunc(attr, mod.__dict__, locals, level=1)
200 setattr(mod, attr, symbol)
201 setattr(mod, attr, symbol)
201
202
202 # Record the importing module references this symbol so we can
203 # Record the importing module references this symbol so we can
203 # replace the symbol with the actual module instance at load
204 # replace the symbol with the actual module instance at load
204 # time.
205 # time.
205 if globalname and isinstance(symbol, _demandmod):
206 if globalname and isinstance(symbol, _demandmod):
206 symbol._addref(globalname)
207 symbol._addref(globalname)
207
208
208 def chainmodules(rootmod, modname):
209 def chainmodules(rootmod, modname):
209 # recurse down the module chain, and return the leaf module
210 # recurse down the module chain, and return the leaf module
210 mod = rootmod
211 mod = rootmod
211 for comp in modname.split('.')[1:]:
212 for comp in modname.split('.')[1:]:
212 if getattr(mod, comp, nothing) is nothing:
213 if getattr(mod, comp, nothing) is nothing:
213 setattr(mod, comp,
214 setattr(mod, comp, _demandmod(comp, mod.__dict__,
214 _demandmod(comp, mod.__dict__, mod.__dict__))
215 mod.__dict__, level=1))
215 mod = getattr(mod, comp)
216 mod = getattr(mod, comp)
216 return mod
217 return mod
217
218
218 if level >= 0:
219 if level >= 0:
219 if name:
220 if name:
220 # "from a import b" or "from .a import b" style
221 # "from a import b" or "from .a import b" style
221 rootmod = _hgextimport(_origimport, name, globals, locals,
222 rootmod = _hgextimport(_origimport, name, globals, locals,
222 level=level)
223 level=level)
223 mod = chainmodules(rootmod, name)
224 mod = chainmodules(rootmod, name)
224 elif _pypy:
225 elif _pypy:
225 # PyPy's __import__ throws an exception if invoked
226 # PyPy's __import__ throws an exception if invoked
226 # with an empty name and no fromlist. Recreate the
227 # with an empty name and no fromlist. Recreate the
227 # desired behaviour by hand.
228 # desired behaviour by hand.
228 mn = globalname
229 mn = globalname
229 mod = sys.modules[mn]
230 mod = sys.modules[mn]
230 if getattr(mod, '__path__', nothing) is nothing:
231 if getattr(mod, '__path__', nothing) is nothing:
231 mn = mn.rsplit('.', 1)[0]
232 mn = mn.rsplit('.', 1)[0]
232 mod = sys.modules[mn]
233 mod = sys.modules[mn]
233 if level > 1:
234 if level > 1:
234 mn = mn.rsplit('.', level - 1)[0]
235 mn = mn.rsplit('.', level - 1)[0]
235 mod = sys.modules[mn]
236 mod = sys.modules[mn]
236 else:
237 else:
237 mod = _hgextimport(_origimport, name, globals, locals,
238 mod = _hgextimport(_origimport, name, globals, locals,
238 level=level)
239 level=level)
239
240
240 for x in fromlist:
241 for x in fromlist:
241 processfromitem(mod, x)
242 processfromitem(mod, x)
242
243
243 return mod
244 return mod
244
245
245 # But, we still need to support lazy loading of standard library and 3rd
246 # But, we still need to support lazy loading of standard library and 3rd
246 # party modules. So handle level == -1.
247 # party modules. So handle level == -1.
247 mod = _hgextimport(_origimport, name, globals, locals)
248 mod = _hgextimport(_origimport, name, globals, locals)
248 mod = chainmodules(mod, name)
249 mod = chainmodules(mod, name)
249
250
250 for x in fromlist:
251 for x in fromlist:
251 processfromitem(mod, x)
252 processfromitem(mod, x)
252
253
253 return mod
254 return mod
254
255
255 ignore = [
256 ignore = [
256 '__future__',
257 '__future__',
257 '_hashlib',
258 '_hashlib',
258 # ImportError during pkg_resources/__init__.py:fixup_namespace_package
259 # ImportError during pkg_resources/__init__.py:fixup_namespace_package
259 '_imp',
260 '_imp',
260 '_xmlplus',
261 '_xmlplus',
261 'fcntl',
262 'fcntl',
262 'win32com.gen_py',
263 'win32com.gen_py',
263 '_winreg', # 2.7 mimetypes needs immediate ImportError
264 '_winreg', # 2.7 mimetypes needs immediate ImportError
264 'pythoncom',
265 'pythoncom',
265 # imported by tarfile, not available under Windows
266 # imported by tarfile, not available under Windows
266 'pwd',
267 'pwd',
267 'grp',
268 'grp',
268 # imported by profile, itself imported by hotshot.stats,
269 # imported by profile, itself imported by hotshot.stats,
269 # not available under Windows
270 # not available under Windows
270 'resource',
271 'resource',
271 # this trips up many extension authors
272 # this trips up many extension authors
272 'gtk',
273 'gtk',
273 # setuptools' pkg_resources.py expects "from __main__ import x" to
274 # setuptools' pkg_resources.py expects "from __main__ import x" to
274 # raise ImportError if x not defined
275 # raise ImportError if x not defined
275 '__main__',
276 '__main__',
276 '_ssl', # conditional imports in the stdlib, issue1964
277 '_ssl', # conditional imports in the stdlib, issue1964
277 '_sre', # issue4920
278 '_sre', # issue4920
278 'rfc822',
279 'rfc822',
279 'mimetools',
280 'mimetools',
280 'sqlalchemy.events', # has import-time side effects (issue5085)
281 'sqlalchemy.events', # has import-time side effects (issue5085)
281 # setuptools 8 expects this module to explode early when not on windows
282 # setuptools 8 expects this module to explode early when not on windows
282 'distutils.msvc9compiler'
283 'distutils.msvc9compiler'
283 ]
284 ]
284
285
285 def isenabled():
286 def isenabled():
286 return builtins.__import__ == _demandimport
287 return builtins.__import__ == _demandimport
287
288
288 def enable():
289 def enable():
289 "enable global demand-loading of modules"
290 "enable global demand-loading of modules"
290 if os.environ.get('HGDEMANDIMPORT') != 'disable':
291 if os.environ.get('HGDEMANDIMPORT') != 'disable':
291 builtins.__import__ = _demandimport
292 builtins.__import__ = _demandimport
292
293
293 def disable():
294 def disable():
294 "disable global demand-loading of modules"
295 "disable global demand-loading of modules"
295 builtins.__import__ = _origimport
296 builtins.__import__ = _origimport
296
297
297 @contextmanager
298 @contextmanager
298 def deactivated():
299 def deactivated():
299 "context manager for disabling demandimport in 'with' blocks"
300 "context manager for disabling demandimport in 'with' blocks"
300 demandenabled = isenabled()
301 demandenabled = isenabled()
301 if demandenabled:
302 if demandenabled:
302 disable()
303 disable()
303
304
304 try:
305 try:
305 yield
306 yield
306 finally:
307 finally:
307 if demandenabled:
308 if demandenabled:
308 enable()
309 enable()
@@ -1,1455 +1,1485 b''
1 Test basic extension support
1 Test basic extension support
2
2
3 $ cat > foobar.py <<EOF
3 $ cat > foobar.py <<EOF
4 > import os
4 > import os
5 > from mercurial import cmdutil, commands
5 > from mercurial import cmdutil, commands
6 > cmdtable = {}
6 > cmdtable = {}
7 > command = cmdutil.command(cmdtable)
7 > command = cmdutil.command(cmdtable)
8 > def uisetup(ui):
8 > def uisetup(ui):
9 > ui.write("uisetup called\\n")
9 > ui.write("uisetup called\\n")
10 > ui.flush()
10 > ui.flush()
11 > def reposetup(ui, repo):
11 > def reposetup(ui, repo):
12 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
12 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
13 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
13 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
14 > ui.flush()
14 > ui.flush()
15 > @command('foo', [], 'hg foo')
15 > @command('foo', [], 'hg foo')
16 > def foo(ui, *args, **kwargs):
16 > def foo(ui, *args, **kwargs):
17 > ui.write("Foo\\n")
17 > ui.write("Foo\\n")
18 > @command('bar', [], 'hg bar', norepo=True)
18 > @command('bar', [], 'hg bar', norepo=True)
19 > def bar(ui, *args, **kwargs):
19 > def bar(ui, *args, **kwargs):
20 > ui.write("Bar\\n")
20 > ui.write("Bar\\n")
21 > EOF
21 > EOF
22 $ abspath=`pwd`/foobar.py
22 $ abspath=`pwd`/foobar.py
23
23
24 $ mkdir barfoo
24 $ mkdir barfoo
25 $ cp foobar.py barfoo/__init__.py
25 $ cp foobar.py barfoo/__init__.py
26 $ barfoopath=`pwd`/barfoo
26 $ barfoopath=`pwd`/barfoo
27
27
28 $ hg init a
28 $ hg init a
29 $ cd a
29 $ cd a
30 $ echo foo > file
30 $ echo foo > file
31 $ hg add file
31 $ hg add file
32 $ hg commit -m 'add file'
32 $ hg commit -m 'add file'
33
33
34 $ echo '[extensions]' >> $HGRCPATH
34 $ echo '[extensions]' >> $HGRCPATH
35 $ echo "foobar = $abspath" >> $HGRCPATH
35 $ echo "foobar = $abspath" >> $HGRCPATH
36 $ hg foo
36 $ hg foo
37 uisetup called
37 uisetup called
38 reposetup called for a
38 reposetup called for a
39 ui == repo.ui
39 ui == repo.ui
40 Foo
40 Foo
41
41
42 $ cd ..
42 $ cd ..
43 $ hg clone a b
43 $ hg clone a b
44 uisetup called
44 uisetup called
45 reposetup called for a
45 reposetup called for a
46 ui == repo.ui
46 ui == repo.ui
47 reposetup called for b
47 reposetup called for b
48 ui == repo.ui
48 ui == repo.ui
49 updating to branch default
49 updating to branch default
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
51
51
52 $ hg bar
52 $ hg bar
53 uisetup called
53 uisetup called
54 Bar
54 Bar
55 $ echo 'foobar = !' >> $HGRCPATH
55 $ echo 'foobar = !' >> $HGRCPATH
56
56
57 module/__init__.py-style
57 module/__init__.py-style
58
58
59 $ echo "barfoo = $barfoopath" >> $HGRCPATH
59 $ echo "barfoo = $barfoopath" >> $HGRCPATH
60 $ cd a
60 $ cd a
61 $ hg foo
61 $ hg foo
62 uisetup called
62 uisetup called
63 reposetup called for a
63 reposetup called for a
64 ui == repo.ui
64 ui == repo.ui
65 Foo
65 Foo
66 $ echo 'barfoo = !' >> $HGRCPATH
66 $ echo 'barfoo = !' >> $HGRCPATH
67
67
68 Check that extensions are loaded in phases:
68 Check that extensions are loaded in phases:
69
69
70 $ cat > foo.py <<EOF
70 $ cat > foo.py <<EOF
71 > import os
71 > import os
72 > name = os.path.basename(__file__).rsplit('.', 1)[0]
72 > name = os.path.basename(__file__).rsplit('.', 1)[0]
73 > print "1) %s imported" % name
73 > print "1) %s imported" % name
74 > def uisetup(ui):
74 > def uisetup(ui):
75 > print "2) %s uisetup" % name
75 > print "2) %s uisetup" % name
76 > def extsetup():
76 > def extsetup():
77 > print "3) %s extsetup" % name
77 > print "3) %s extsetup" % name
78 > def reposetup(ui, repo):
78 > def reposetup(ui, repo):
79 > print "4) %s reposetup" % name
79 > print "4) %s reposetup" % name
80 > EOF
80 > EOF
81
81
82 $ cp foo.py bar.py
82 $ cp foo.py bar.py
83 $ echo 'foo = foo.py' >> $HGRCPATH
83 $ echo 'foo = foo.py' >> $HGRCPATH
84 $ echo 'bar = bar.py' >> $HGRCPATH
84 $ echo 'bar = bar.py' >> $HGRCPATH
85
85
86 Command with no output, we just want to see the extensions loaded:
86 Command with no output, we just want to see the extensions loaded:
87
87
88 $ hg paths
88 $ hg paths
89 1) foo imported
89 1) foo imported
90 1) bar imported
90 1) bar imported
91 2) foo uisetup
91 2) foo uisetup
92 2) bar uisetup
92 2) bar uisetup
93 3) foo extsetup
93 3) foo extsetup
94 3) bar extsetup
94 3) bar extsetup
95 4) foo reposetup
95 4) foo reposetup
96 4) bar reposetup
96 4) bar reposetup
97
97
98 Check hgweb's load order:
98 Check hgweb's load order:
99
99
100 $ cat > hgweb.cgi <<EOF
100 $ cat > hgweb.cgi <<EOF
101 > #!/usr/bin/env python
101 > #!/usr/bin/env python
102 > from mercurial import demandimport; demandimport.enable()
102 > from mercurial import demandimport; demandimport.enable()
103 > from mercurial.hgweb import hgweb
103 > from mercurial.hgweb import hgweb
104 > from mercurial.hgweb import wsgicgi
104 > from mercurial.hgweb import wsgicgi
105 > application = hgweb('.', 'test repo')
105 > application = hgweb('.', 'test repo')
106 > wsgicgi.launch(application)
106 > wsgicgi.launch(application)
107 > EOF
107 > EOF
108
108
109 $ REQUEST_METHOD='GET' PATH_INFO='/' SCRIPT_NAME='' QUERY_STRING='' \
109 $ REQUEST_METHOD='GET' PATH_INFO='/' SCRIPT_NAME='' QUERY_STRING='' \
110 > SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
110 > SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
111 > | grep '^[0-9]) ' # ignores HTML output
111 > | grep '^[0-9]) ' # ignores HTML output
112 1) foo imported
112 1) foo imported
113 1) bar imported
113 1) bar imported
114 2) foo uisetup
114 2) foo uisetup
115 2) bar uisetup
115 2) bar uisetup
116 3) foo extsetup
116 3) foo extsetup
117 3) bar extsetup
117 3) bar extsetup
118 4) foo reposetup
118 4) foo reposetup
119 4) bar reposetup
119 4) bar reposetup
120
120
121 $ echo 'foo = !' >> $HGRCPATH
121 $ echo 'foo = !' >> $HGRCPATH
122 $ echo 'bar = !' >> $HGRCPATH
122 $ echo 'bar = !' >> $HGRCPATH
123
123
124 Check "from __future__ import absolute_import" support for external libraries
124 Check "from __future__ import absolute_import" support for external libraries
125
125
126 #if windows
126 #if windows
127 $ PATHSEP=";"
127 $ PATHSEP=";"
128 #else
128 #else
129 $ PATHSEP=":"
129 $ PATHSEP=":"
130 #endif
130 #endif
131 $ export PATHSEP
131 $ export PATHSEP
132
132
133 $ mkdir $TESTTMP/libroot
133 $ mkdir $TESTTMP/libroot
134 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
134 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
135 $ mkdir $TESTTMP/libroot/mod
135 $ mkdir $TESTTMP/libroot/mod
136 $ touch $TESTTMP/libroot/mod/__init__.py
136 $ touch $TESTTMP/libroot/mod/__init__.py
137 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
137 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
138
138
139 #if absimport
139 #if absimport
140 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF
140 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF
141 > from __future__ import absolute_import
141 > from __future__ import absolute_import
142 > import ambig # should load "libroot/ambig.py"
142 > import ambig # should load "libroot/ambig.py"
143 > s = ambig.s
143 > s = ambig.s
144 > EOF
144 > EOF
145 $ cat > loadabs.py <<EOF
145 $ cat > loadabs.py <<EOF
146 > import mod.ambigabs as ambigabs
146 > import mod.ambigabs as ambigabs
147 > def extsetup():
147 > def extsetup():
148 > print 'ambigabs.s=%s' % ambigabs.s
148 > print 'ambigabs.s=%s' % ambigabs.s
149 > EOF
149 > EOF
150 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
150 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
151 ambigabs.s=libroot/ambig.py
151 ambigabs.s=libroot/ambig.py
152 $TESTTMP/a (glob)
152 $TESTTMP/a (glob)
153 #endif
153 #endif
154
154
155 #if no-py3k
155 #if no-py3k
156 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF
156 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF
157 > import ambig # should load "libroot/mod/ambig.py"
157 > import ambig # should load "libroot/mod/ambig.py"
158 > s = ambig.s
158 > s = ambig.s
159 > EOF
159 > EOF
160 $ cat > loadrel.py <<EOF
160 $ cat > loadrel.py <<EOF
161 > import mod.ambigrel as ambigrel
161 > import mod.ambigrel as ambigrel
162 > def extsetup():
162 > def extsetup():
163 > print 'ambigrel.s=%s' % ambigrel.s
163 > print 'ambigrel.s=%s' % ambigrel.s
164 > EOF
164 > EOF
165 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
165 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
166 ambigrel.s=libroot/mod/ambig.py
166 ambigrel.s=libroot/mod/ambig.py
167 $TESTTMP/a (glob)
167 $TESTTMP/a (glob)
168 #endif
168 #endif
169
169
170 Check absolute/relative import of extension specific modules
170 Check absolute/relative import of extension specific modules
171
171
172 $ mkdir $TESTTMP/extroot
172 $ mkdir $TESTTMP/extroot
173 $ cat > $TESTTMP/extroot/bar.py <<EOF
173 $ cat > $TESTTMP/extroot/bar.py <<EOF
174 > s = 'this is extroot.bar'
174 > s = 'this is extroot.bar'
175 > EOF
175 > EOF
176 $ mkdir $TESTTMP/extroot/sub1
176 $ mkdir $TESTTMP/extroot/sub1
177 $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF
177 $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF
178 > s = 'this is extroot.sub1.__init__'
178 > s = 'this is extroot.sub1.__init__'
179 > EOF
179 > EOF
180 $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF
180 $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF
181 > s = 'this is extroot.sub1.baz'
181 > s = 'this is extroot.sub1.baz'
182 > EOF
182 > EOF
183 $ cat > $TESTTMP/extroot/__init__.py <<EOF
183 $ cat > $TESTTMP/extroot/__init__.py <<EOF
184 > s = 'this is extroot.__init__'
184 > s = 'this is extroot.__init__'
185 > import foo
185 > import foo
186 > def extsetup(ui):
186 > def extsetup(ui):
187 > ui.write('(extroot) ', foo.func(), '\n')
187 > ui.write('(extroot) ', foo.func(), '\n')
188 > ui.flush()
188 > ui.flush()
189 > EOF
189 > EOF
190
190
191 $ cat > $TESTTMP/extroot/foo.py <<EOF
191 $ cat > $TESTTMP/extroot/foo.py <<EOF
192 > # test absolute import
192 > # test absolute import
193 > buf = []
193 > buf = []
194 > def func():
194 > def func():
195 > # "not locals" case
195 > # "not locals" case
196 > import extroot.bar
196 > import extroot.bar
197 > buf.append('import extroot.bar in func(): %s' % extroot.bar.s)
197 > buf.append('import extroot.bar in func(): %s' % extroot.bar.s)
198 > return '\n(extroot) '.join(buf)
198 > return '\n(extroot) '.join(buf)
199 > # "fromlist == ('*',)" case
199 > # "fromlist == ('*',)" case
200 > from extroot.bar import *
200 > from extroot.bar import *
201 > buf.append('from extroot.bar import *: %s' % s)
201 > buf.append('from extroot.bar import *: %s' % s)
202 > # "not fromlist" and "if '.' in name" case
202 > # "not fromlist" and "if '.' in name" case
203 > import extroot.sub1.baz
203 > import extroot.sub1.baz
204 > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
204 > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
205 > # "not fromlist" and NOT "if '.' in name" case
205 > # "not fromlist" and NOT "if '.' in name" case
206 > import extroot
206 > import extroot
207 > buf.append('import extroot: %s' % extroot.s)
207 > buf.append('import extroot: %s' % extroot.s)
208 > # NOT "not fromlist" and NOT "level != -1" case
208 > # NOT "not fromlist" and NOT "level != -1" case
209 > from extroot.bar import s
209 > from extroot.bar import s
210 > buf.append('from extroot.bar import s: %s' % s)
210 > buf.append('from extroot.bar import s: %s' % s)
211 > EOF
211 > EOF
212 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
212 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
213 (extroot) from extroot.bar import *: this is extroot.bar
213 (extroot) from extroot.bar import *: this is extroot.bar
214 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
214 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
215 (extroot) import extroot: this is extroot.__init__
215 (extroot) import extroot: this is extroot.__init__
216 (extroot) from extroot.bar import s: this is extroot.bar
216 (extroot) from extroot.bar import s: this is extroot.bar
217 (extroot) import extroot.bar in func(): this is extroot.bar
217 (extroot) import extroot.bar in func(): this is extroot.bar
218 $TESTTMP/a (glob)
218 $TESTTMP/a (glob)
219
219
220 #if no-py3k
220 #if no-py3k
221 $ rm "$TESTTMP"/extroot/foo.*
221 $ rm "$TESTTMP"/extroot/foo.*
222 $ cat > $TESTTMP/extroot/foo.py <<EOF
222 $ cat > $TESTTMP/extroot/foo.py <<EOF
223 > # test relative import
223 > # test relative import
224 > buf = []
224 > buf = []
225 > def func():
225 > def func():
226 > # "not locals" case
226 > # "not locals" case
227 > import bar
227 > import bar
228 > buf.append('import bar in func(): %s' % bar.s)
228 > buf.append('import bar in func(): %s' % bar.s)
229 > return '\n(extroot) '.join(buf)
229 > return '\n(extroot) '.join(buf)
230 > # "fromlist == ('*',)" case
230 > # "fromlist == ('*',)" case
231 > from bar import *
231 > from bar import *
232 > buf.append('from bar import *: %s' % s)
232 > buf.append('from bar import *: %s' % s)
233 > # "not fromlist" and "if '.' in name" case
233 > # "not fromlist" and "if '.' in name" case
234 > import sub1.baz
234 > import sub1.baz
235 > buf.append('import sub1.baz: %s' % sub1.baz.s)
235 > buf.append('import sub1.baz: %s' % sub1.baz.s)
236 > # "not fromlist" and NOT "if '.' in name" case
236 > # "not fromlist" and NOT "if '.' in name" case
237 > import sub1
237 > import sub1
238 > buf.append('import sub1: %s' % sub1.s)
238 > buf.append('import sub1: %s' % sub1.s)
239 > # NOT "not fromlist" and NOT "level != -1" case
239 > # NOT "not fromlist" and NOT "level != -1" case
240 > from bar import s
240 > from bar import s
241 > buf.append('from bar import s: %s' % s)
241 > buf.append('from bar import s: %s' % s)
242 > EOF
242 > EOF
243 $ hg --config extensions.extroot=$TESTTMP/extroot root
243 $ hg --config extensions.extroot=$TESTTMP/extroot root
244 (extroot) from bar import *: this is extroot.bar
244 (extroot) from bar import *: this is extroot.bar
245 (extroot) import sub1.baz: this is extroot.sub1.baz
245 (extroot) import sub1.baz: this is extroot.sub1.baz
246 (extroot) import sub1: this is extroot.sub1.__init__
246 (extroot) import sub1: this is extroot.sub1.__init__
247 (extroot) from bar import s: this is extroot.bar
247 (extroot) from bar import s: this is extroot.bar
248 (extroot) import bar in func(): this is extroot.bar
248 (extroot) import bar in func(): this is extroot.bar
249 $TESTTMP/a (glob)
249 $TESTTMP/a (glob)
250 #endif
250 #endif
251
251
252 #if absimport
252 #if absimport
253
253
254 Examine whether module loading is delayed until actual refering, even
254 Examine whether module loading is delayed until actual refering, even
255 though module is imported with "absolute_import" feature.
255 though module is imported with "absolute_import" feature.
256
256
257 Files below in each packages are used for descirbed purpose:
257 Files below in each packages are used for descirbed purpose:
258
258
259 - "called": examine whether "from MODULE import ATTR" works correctly
259 - "called": examine whether "from MODULE import ATTR" works correctly
260 - "unused": examine whether loading is delayed correctly
260 - "unused": examine whether loading is delayed correctly
261 - "used": examine whether "from PACKAGE import MODULE" works correctly
261 - "used": examine whether "from PACKAGE import MODULE" works correctly
262
262
263 Package hierarchy is needed to examine whether demand importing works
263 Package hierarchy is needed to examine whether demand importing works
264 as expected for "from SUB.PACK.AGE import MODULE".
264 as expected for "from SUB.PACK.AGE import MODULE".
265
265
266 Setup "external library" to be imported with "absolute_import"
266 Setup "external library" to be imported with "absolute_import"
267 feature.
267 feature.
268
268
269 $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2
269 $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2
270 $ touch $TESTTMP/extlibroot/__init__.py
270 $ touch $TESTTMP/extlibroot/__init__.py
271 $ touch $TESTTMP/extlibroot/lsub1/__init__.py
271 $ touch $TESTTMP/extlibroot/lsub1/__init__.py
272 $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py
272 $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py
273
273
274 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<EOF
274 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<EOF
275 > def func():
275 > def func():
276 > return "this is extlibroot.lsub1.lsub2.called.func()"
276 > return "this is extlibroot.lsub1.lsub2.called.func()"
277 > EOF
277 > EOF
278 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<EOF
278 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<EOF
279 > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally")
279 > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally")
280 > EOF
280 > EOF
281 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<EOF
281 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<EOF
282 > detail = "this is extlibroot.lsub1.lsub2.used"
282 > detail = "this is extlibroot.lsub1.lsub2.used"
283 > EOF
283 > EOF
284
284
285 Setup sub-package of "external library", which causes instantiation of
285 Setup sub-package of "external library", which causes instantiation of
286 demandmod in "recurse down the module chain" code path. Relative
286 demandmod in "recurse down the module chain" code path. Relative
287 importing with "absolute_import" feature isn't tested, because "level
287 importing with "absolute_import" feature isn't tested, because "level
288 >=1 " doesn't cause instantiation of demandmod.
288 >=1 " doesn't cause instantiation of demandmod.
289
289
290 $ mkdir -p $TESTTMP/extlibroot/recursedown/abs
290 $ mkdir -p $TESTTMP/extlibroot/recursedown/abs
291 $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<EOF
291 $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<EOF
292 > detail = "this is extlibroot.recursedown.abs.used"
292 > detail = "this is extlibroot.recursedown.abs.used"
293 > EOF
293 > EOF
294 $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<EOF
294 $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<EOF
295 > from __future__ import absolute_import
295 > from __future__ import absolute_import
296 > from extlibroot.recursedown.abs.used import detail
296 > from extlibroot.recursedown.abs.used import detail
297 > EOF
297 > EOF
298
298
299 $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy
299 $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy
300 $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<EOF
300 $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<EOF
301 > detail = "this is extlibroot.recursedown.legacy.used"
301 > detail = "this is extlibroot.recursedown.legacy.used"
302 > EOF
302 > EOF
303 $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<EOF
303 $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<EOF
304 > # legacy style (level == -1) import
304 > # legacy style (level == -1) import
305 > from extlibroot.recursedown.legacy.used import detail
305 > from extlibroot.recursedown.legacy.used import detail
306 > EOF
306 > EOF
307
307
308 $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<EOF
308 $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<EOF
309 > from __future__ import absolute_import
309 > from __future__ import absolute_import
310 > from extlibroot.recursedown.abs import detail as absdetail
310 > from extlibroot.recursedown.abs import detail as absdetail
311 > from .legacy import detail as legacydetail
311 > from .legacy import detail as legacydetail
312 > EOF
312 > EOF
313
313
314 Setup extension local modules to be imported with "absolute_import"
314 Setup extension local modules to be imported with "absolute_import"
315 feature.
315 feature.
316
316
317 $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2
317 $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2
318 $ touch $TESTTMP/absextroot/xsub1/__init__.py
318 $ touch $TESTTMP/absextroot/xsub1/__init__.py
319 $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py
319 $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py
320
320
321 $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<EOF
321 $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<EOF
322 > def func():
322 > def func():
323 > return "this is absextroot.xsub1.xsub2.called.func()"
323 > return "this is absextroot.xsub1.xsub2.called.func()"
324 > EOF
324 > EOF
325 $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<EOF
325 $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<EOF
326 > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally")
326 > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally")
327 > EOF
327 > EOF
328 $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<EOF
328 $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<EOF
329 > detail = "this is absextroot.xsub1.xsub2.used"
329 > detail = "this is absextroot.xsub1.xsub2.used"
330 > EOF
330 > EOF
331
331
332 Setup extension local modules to examine whether demand importing
332 Setup extension local modules to examine whether demand importing
333 works as expected in "level > 1" case.
333 works as expected in "level > 1" case.
334
334
335 $ cat > $TESTTMP/absextroot/relimportee.py <<EOF
335 $ cat > $TESTTMP/absextroot/relimportee.py <<EOF
336 > detail = "this is absextroot.relimportee"
336 > detail = "this is absextroot.relimportee"
337 > EOF
337 > EOF
338 $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<EOF
338 $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<EOF
339 > from __future__ import absolute_import
339 > from __future__ import absolute_import
340 > from ... import relimportee
340 > from ... import relimportee
341 > detail = "this relimporter imports %r" % (relimportee.detail)
341 > detail = "this relimporter imports %r" % (relimportee.detail)
342 > EOF
342 > EOF
343
343
344 Setup modules, which actually import extension local modules at
344 Setup modules, which actually import extension local modules at
345 runtime.
345 runtime.
346
346
347 $ cat > $TESTTMP/absextroot/absolute.py << EOF
347 $ cat > $TESTTMP/absextroot/absolute.py << EOF
348 > from __future__ import absolute_import
348 > from __future__ import absolute_import
349 >
349 >
350 > # import extension local modules absolutely (level = 0)
350 > # import extension local modules absolutely (level = 0)
351 > from absextroot.xsub1.xsub2 import used, unused
351 > from absextroot.xsub1.xsub2 import used, unused
352 > from absextroot.xsub1.xsub2.called import func
352 > from absextroot.xsub1.xsub2.called import func
353 >
353 >
354 > def getresult():
354 > def getresult():
355 > result = []
355 > result = []
356 > result.append(used.detail)
356 > result.append(used.detail)
357 > result.append(func())
357 > result.append(func())
358 > return result
358 > return result
359 > EOF
359 > EOF
360
360
361 $ cat > $TESTTMP/absextroot/relative.py << EOF
361 $ cat > $TESTTMP/absextroot/relative.py << EOF
362 > from __future__ import absolute_import
362 > from __future__ import absolute_import
363 >
363 >
364 > # import extension local modules relatively (level == 1)
364 > # import extension local modules relatively (level == 1)
365 > from .xsub1.xsub2 import used, unused
365 > from .xsub1.xsub2 import used, unused
366 > from .xsub1.xsub2.called import func
366 > from .xsub1.xsub2.called import func
367 >
367 >
368 > # import a module, which implies "importing with level > 1"
368 > # import a module, which implies "importing with level > 1"
369 > from .xsub1.xsub2 import relimporter
369 > from .xsub1.xsub2 import relimporter
370 >
370 >
371 > def getresult():
371 > def getresult():
372 > result = []
372 > result = []
373 > result.append(used.detail)
373 > result.append(used.detail)
374 > result.append(func())
374 > result.append(func())
375 > result.append(relimporter.detail)
375 > result.append(relimporter.detail)
376 > return result
376 > return result
377 > EOF
377 > EOF
378
378
379 Setup main procedure of extension.
379 Setup main procedure of extension.
380
380
381 $ cat > $TESTTMP/absextroot/__init__.py <<EOF
381 $ cat > $TESTTMP/absextroot/__init__.py <<EOF
382 > from __future__ import absolute_import
382 > from __future__ import absolute_import
383 > from mercurial import cmdutil
383 > from mercurial import cmdutil
384 > cmdtable = {}
384 > cmdtable = {}
385 > command = cmdutil.command(cmdtable)
385 > command = cmdutil.command(cmdtable)
386 >
386 >
387 > # "absolute" and "relative" shouldn't be imported before actual
387 > # "absolute" and "relative" shouldn't be imported before actual
388 > # command execution, because (1) they import same modules, and (2)
388 > # command execution, because (1) they import same modules, and (2)
389 > # preceding import (= instantiate "demandmod" object instead of
389 > # preceding import (= instantiate "demandmod" object instead of
390 > # real "module" object) might hide problem of succeeding import.
390 > # real "module" object) might hide problem of succeeding import.
391 >
391 >
392 > @command('showabsolute', [], norepo=True)
392 > @command('showabsolute', [], norepo=True)
393 > def showabsolute(ui, *args, **opts):
393 > def showabsolute(ui, *args, **opts):
394 > from absextroot import absolute
394 > from absextroot import absolute
395 > ui.write('ABS: %s\n' % '\nABS: '.join(absolute.getresult()))
395 > ui.write('ABS: %s\n' % '\nABS: '.join(absolute.getresult()))
396 >
396 >
397 > @command('showrelative', [], norepo=True)
397 > @command('showrelative', [], norepo=True)
398 > def showrelative(ui, *args, **opts):
398 > def showrelative(ui, *args, **opts):
399 > from . import relative
399 > from . import relative
400 > ui.write('REL: %s\n' % '\nREL: '.join(relative.getresult()))
400 > ui.write('REL: %s\n' % '\nREL: '.join(relative.getresult()))
401 >
401 >
402 > # import modules from external library
402 > # import modules from external library
403 > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused
403 > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused
404 > from extlibroot.lsub1.lsub2.called import func as lfunc
404 > from extlibroot.lsub1.lsub2.called import func as lfunc
405 > from extlibroot.recursedown import absdetail, legacydetail
405 > from extlibroot.recursedown import absdetail, legacydetail
406 >
406 >
407 > def uisetup(ui):
407 > def uisetup(ui):
408 > result = []
408 > result = []
409 > result.append(lused.detail)
409 > result.append(lused.detail)
410 > result.append(lfunc())
410 > result.append(lfunc())
411 > result.append(absdetail)
411 > result.append(absdetail)
412 > result.append(legacydetail)
412 > result.append(legacydetail)
413 > ui.write('LIB: %s\n' % '\nLIB: '.join(result))
413 > ui.write('LIB: %s\n' % '\nLIB: '.join(result))
414 > EOF
414 > EOF
415
415
416 Examine module importing.
416 Examine module importing.
417
417
418 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute)
418 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute)
419 LIB: this is extlibroot.lsub1.lsub2.used
419 LIB: this is extlibroot.lsub1.lsub2.used
420 LIB: this is extlibroot.lsub1.lsub2.called.func()
420 LIB: this is extlibroot.lsub1.lsub2.called.func()
421 LIB: this is extlibroot.recursedown.abs.used
421 LIB: this is extlibroot.recursedown.abs.used
422 LIB: this is extlibroot.recursedown.legacy.used
422 LIB: this is extlibroot.recursedown.legacy.used
423 ABS: this is absextroot.xsub1.xsub2.used
423 ABS: this is absextroot.xsub1.xsub2.used
424 ABS: this is absextroot.xsub1.xsub2.called.func()
424 ABS: this is absextroot.xsub1.xsub2.called.func()
425
425
426 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative)
426 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative)
427 LIB: this is extlibroot.lsub1.lsub2.used
427 LIB: this is extlibroot.lsub1.lsub2.used
428 LIB: this is extlibroot.lsub1.lsub2.called.func()
428 LIB: this is extlibroot.lsub1.lsub2.called.func()
429 LIB: this is extlibroot.recursedown.abs.used
429 LIB: this is extlibroot.recursedown.abs.used
430 LIB: this is extlibroot.recursedown.legacy.used
430 LIB: this is extlibroot.recursedown.legacy.used
431 REL: this is absextroot.xsub1.xsub2.used
431 REL: this is absextroot.xsub1.xsub2.used
432 REL: this is absextroot.xsub1.xsub2.called.func()
432 REL: this is absextroot.xsub1.xsub2.called.func()
433 REL: this relimporter imports 'this is absextroot.relimportee'
433 REL: this relimporter imports 'this is absextroot.relimportee'
434
434
435 Examine whether sub-module is imported relatively as expected.
436
437 See also issue5208 for detail about example case on Python 3.x.
438
439 $ f -q $TESTTMP/extlibroot/lsub1/lsub2/notexist.py
440 $TESTTMP/extlibroot/lsub1/lsub2/notexist.py: file not found
441
442 $ cat > $TESTTMP/notexist.py <<EOF
443 > text = 'notexist.py at root is loaded unintentionally\n'
444 > EOF
445
446 $ cat > $TESTTMP/checkrelativity.py <<EOF
447 > from mercurial import cmdutil
448 > cmdtable = {}
449 > command = cmdutil.command(cmdtable)
450 >
451 > # demand import avoids failure of importing notexist here
452 > import extlibroot.lsub1.lsub2.notexist
453 >
454 > @command('checkrelativity', [], norepo=True)
455 > def checkrelativity(ui, *args, **opts):
456 > try:
457 > ui.write(extlibroot.lsub1.lsub2.notexist.text)
458 > return 1 # unintentional success
459 > except ImportError:
460 > pass # intentional failure
461 > EOF
462
463 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.checkrelativity=$TESTTMP/checkrelativity.py checkrelativity)
464
435 #endif
465 #endif
436
466
437 $ cd ..
467 $ cd ..
438
468
439 hide outer repo
469 hide outer repo
440 $ hg init
470 $ hg init
441
471
442 $ cat > empty.py <<EOF
472 $ cat > empty.py <<EOF
443 > '''empty cmdtable
473 > '''empty cmdtable
444 > '''
474 > '''
445 > cmdtable = {}
475 > cmdtable = {}
446 > EOF
476 > EOF
447 $ emptypath=`pwd`/empty.py
477 $ emptypath=`pwd`/empty.py
448 $ echo "empty = $emptypath" >> $HGRCPATH
478 $ echo "empty = $emptypath" >> $HGRCPATH
449 $ hg help empty
479 $ hg help empty
450 empty extension - empty cmdtable
480 empty extension - empty cmdtable
451
481
452 no commands defined
482 no commands defined
453
483
454
484
455 $ echo 'empty = !' >> $HGRCPATH
485 $ echo 'empty = !' >> $HGRCPATH
456
486
457 $ cat > debugextension.py <<EOF
487 $ cat > debugextension.py <<EOF
458 > '''only debugcommands
488 > '''only debugcommands
459 > '''
489 > '''
460 > from mercurial import cmdutil
490 > from mercurial import cmdutil
461 > cmdtable = {}
491 > cmdtable = {}
462 > command = cmdutil.command(cmdtable)
492 > command = cmdutil.command(cmdtable)
463 > @command('debugfoobar', [], 'hg debugfoobar')
493 > @command('debugfoobar', [], 'hg debugfoobar')
464 > def debugfoobar(ui, repo, *args, **opts):
494 > def debugfoobar(ui, repo, *args, **opts):
465 > "yet another debug command"
495 > "yet another debug command"
466 > pass
496 > pass
467 > @command('foo', [], 'hg foo')
497 > @command('foo', [], 'hg foo')
468 > def foo(ui, repo, *args, **opts):
498 > def foo(ui, repo, *args, **opts):
469 > """yet another foo command
499 > """yet another foo command
470 > This command has been DEPRECATED since forever.
500 > This command has been DEPRECATED since forever.
471 > """
501 > """
472 > pass
502 > pass
473 > EOF
503 > EOF
474 $ debugpath=`pwd`/debugextension.py
504 $ debugpath=`pwd`/debugextension.py
475 $ echo "debugextension = $debugpath" >> $HGRCPATH
505 $ echo "debugextension = $debugpath" >> $HGRCPATH
476
506
477 $ hg help debugextension
507 $ hg help debugextension
478 hg debugextensions
508 hg debugextensions
479
509
480 show information about active extensions
510 show information about active extensions
481
511
482 options:
512 options:
483
513
484 (some details hidden, use --verbose to show complete help)
514 (some details hidden, use --verbose to show complete help)
485
515
486
516
487 $ hg --verbose help debugextension
517 $ hg --verbose help debugextension
488 hg debugextensions
518 hg debugextensions
489
519
490 show information about active extensions
520 show information about active extensions
491
521
492 options:
522 options:
493
523
494 -T --template TEMPLATE display with template (EXPERIMENTAL)
524 -T --template TEMPLATE display with template (EXPERIMENTAL)
495
525
496 global options ([+] can be repeated):
526 global options ([+] can be repeated):
497
527
498 -R --repository REPO repository root directory or name of overlay bundle
528 -R --repository REPO repository root directory or name of overlay bundle
499 file
529 file
500 --cwd DIR change working directory
530 --cwd DIR change working directory
501 -y --noninteractive do not prompt, automatically pick the first choice for
531 -y --noninteractive do not prompt, automatically pick the first choice for
502 all prompts
532 all prompts
503 -q --quiet suppress output
533 -q --quiet suppress output
504 -v --verbose enable additional output
534 -v --verbose enable additional output
505 --config CONFIG [+] set/override config option (use 'section.name=value')
535 --config CONFIG [+] set/override config option (use 'section.name=value')
506 --debug enable debugging output
536 --debug enable debugging output
507 --debugger start debugger
537 --debugger start debugger
508 --encoding ENCODE set the charset encoding (default: ascii)
538 --encoding ENCODE set the charset encoding (default: ascii)
509 --encodingmode MODE set the charset encoding mode (default: strict)
539 --encodingmode MODE set the charset encoding mode (default: strict)
510 --traceback always print a traceback on exception
540 --traceback always print a traceback on exception
511 --time time how long the command takes
541 --time time how long the command takes
512 --profile print command execution profile
542 --profile print command execution profile
513 --version output version information and exit
543 --version output version information and exit
514 -h --help display help and exit
544 -h --help display help and exit
515 --hidden consider hidden changesets
545 --hidden consider hidden changesets
516
546
517
547
518
548
519
549
520
550
521
551
522 $ hg --debug help debugextension
552 $ hg --debug help debugextension
523 hg debugextensions
553 hg debugextensions
524
554
525 show information about active extensions
555 show information about active extensions
526
556
527 options:
557 options:
528
558
529 -T --template TEMPLATE display with template (EXPERIMENTAL)
559 -T --template TEMPLATE display with template (EXPERIMENTAL)
530
560
531 global options ([+] can be repeated):
561 global options ([+] can be repeated):
532
562
533 -R --repository REPO repository root directory or name of overlay bundle
563 -R --repository REPO repository root directory or name of overlay bundle
534 file
564 file
535 --cwd DIR change working directory
565 --cwd DIR change working directory
536 -y --noninteractive do not prompt, automatically pick the first choice for
566 -y --noninteractive do not prompt, automatically pick the first choice for
537 all prompts
567 all prompts
538 -q --quiet suppress output
568 -q --quiet suppress output
539 -v --verbose enable additional output
569 -v --verbose enable additional output
540 --config CONFIG [+] set/override config option (use 'section.name=value')
570 --config CONFIG [+] set/override config option (use 'section.name=value')
541 --debug enable debugging output
571 --debug enable debugging output
542 --debugger start debugger
572 --debugger start debugger
543 --encoding ENCODE set the charset encoding (default: ascii)
573 --encoding ENCODE set the charset encoding (default: ascii)
544 --encodingmode MODE set the charset encoding mode (default: strict)
574 --encodingmode MODE set the charset encoding mode (default: strict)
545 --traceback always print a traceback on exception
575 --traceback always print a traceback on exception
546 --time time how long the command takes
576 --time time how long the command takes
547 --profile print command execution profile
577 --profile print command execution profile
548 --version output version information and exit
578 --version output version information and exit
549 -h --help display help and exit
579 -h --help display help and exit
550 --hidden consider hidden changesets
580 --hidden consider hidden changesets
551
581
552
582
553
583
554
584
555
585
556 $ echo 'debugextension = !' >> $HGRCPATH
586 $ echo 'debugextension = !' >> $HGRCPATH
557
587
558 Asking for help about a deprecated extension should do something useful:
588 Asking for help about a deprecated extension should do something useful:
559
589
560 $ hg help glog
590 $ hg help glog
561 'glog' is provided by the following extension:
591 'glog' is provided by the following extension:
562
592
563 graphlog command to view revision graphs from a shell (DEPRECATED)
593 graphlog command to view revision graphs from a shell (DEPRECATED)
564
594
565 (use "hg help extensions" for information on enabling extensions)
595 (use "hg help extensions" for information on enabling extensions)
566
596
567 Extension module help vs command help:
597 Extension module help vs command help:
568
598
569 $ echo 'extdiff =' >> $HGRCPATH
599 $ echo 'extdiff =' >> $HGRCPATH
570 $ hg help extdiff
600 $ hg help extdiff
571 hg extdiff [OPT]... [FILE]...
601 hg extdiff [OPT]... [FILE]...
572
602
573 use external program to diff repository (or selected files)
603 use external program to diff repository (or selected files)
574
604
575 Show differences between revisions for the specified files, using an
605 Show differences between revisions for the specified files, using an
576 external program. The default program used is diff, with default options
606 external program. The default program used is diff, with default options
577 "-Npru".
607 "-Npru".
578
608
579 To select a different program, use the -p/--program option. The program
609 To select a different program, use the -p/--program option. The program
580 will be passed the names of two directories to compare. To pass additional
610 will be passed the names of two directories to compare. To pass additional
581 options to the program, use -o/--option. These will be passed before the
611 options to the program, use -o/--option. These will be passed before the
582 names of the directories to compare.
612 names of the directories to compare.
583
613
584 When two revision arguments are given, then changes are shown between
614 When two revision arguments are given, then changes are shown between
585 those revisions. If only one revision is specified then that revision is
615 those revisions. If only one revision is specified then that revision is
586 compared to the working directory, and, when no revisions are specified,
616 compared to the working directory, and, when no revisions are specified,
587 the working directory files are compared to its parent.
617 the working directory files are compared to its parent.
588
618
589 (use "hg help -e extdiff" to show help for the extdiff extension)
619 (use "hg help -e extdiff" to show help for the extdiff extension)
590
620
591 options ([+] can be repeated):
621 options ([+] can be repeated):
592
622
593 -p --program CMD comparison program to run
623 -p --program CMD comparison program to run
594 -o --option OPT [+] pass option to comparison program
624 -o --option OPT [+] pass option to comparison program
595 -r --rev REV [+] revision
625 -r --rev REV [+] revision
596 -c --change REV change made by revision
626 -c --change REV change made by revision
597 --patch compare patches for two revisions
627 --patch compare patches for two revisions
598 -I --include PATTERN [+] include names matching the given patterns
628 -I --include PATTERN [+] include names matching the given patterns
599 -X --exclude PATTERN [+] exclude names matching the given patterns
629 -X --exclude PATTERN [+] exclude names matching the given patterns
600 -S --subrepos recurse into subrepositories
630 -S --subrepos recurse into subrepositories
601
631
602 (some details hidden, use --verbose to show complete help)
632 (some details hidden, use --verbose to show complete help)
603
633
604
634
605
635
606
636
607
637
608
638
609
639
610
640
611
641
612
642
613 $ hg help --extension extdiff
643 $ hg help --extension extdiff
614 extdiff extension - command to allow external programs to compare revisions
644 extdiff extension - command to allow external programs to compare revisions
615
645
616 The extdiff Mercurial extension allows you to use external programs to compare
646 The extdiff Mercurial extension allows you to use external programs to compare
617 revisions, or revision with working directory. The external diff programs are
647 revisions, or revision with working directory. The external diff programs are
618 called with a configurable set of options and two non-option arguments: paths
648 called with a configurable set of options and two non-option arguments: paths
619 to directories containing snapshots of files to compare.
649 to directories containing snapshots of files to compare.
620
650
621 The extdiff extension also allows you to configure new diff commands, so you
651 The extdiff extension also allows you to configure new diff commands, so you
622 do not need to type 'hg extdiff -p kdiff3' always.
652 do not need to type 'hg extdiff -p kdiff3' always.
623
653
624 [extdiff]
654 [extdiff]
625 # add new command that runs GNU diff(1) in 'context diff' mode
655 # add new command that runs GNU diff(1) in 'context diff' mode
626 cdiff = gdiff -Nprc5
656 cdiff = gdiff -Nprc5
627 ## or the old way:
657 ## or the old way:
628 #cmd.cdiff = gdiff
658 #cmd.cdiff = gdiff
629 #opts.cdiff = -Nprc5
659 #opts.cdiff = -Nprc5
630
660
631 # add new command called meld, runs meld (no need to name twice). If
661 # add new command called meld, runs meld (no need to name twice). If
632 # the meld executable is not available, the meld tool in [merge-tools]
662 # the meld executable is not available, the meld tool in [merge-tools]
633 # will be used, if available
663 # will be used, if available
634 meld =
664 meld =
635
665
636 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
666 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
637 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
667 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
638 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
668 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
639 # your .vimrc
669 # your .vimrc
640 vimdiff = gvim -f "+next" \
670 vimdiff = gvim -f "+next" \
641 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
671 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
642
672
643 Tool arguments can include variables that are expanded at runtime:
673 Tool arguments can include variables that are expanded at runtime:
644
674
645 $parent1, $plabel1 - filename, descriptive label of first parent
675 $parent1, $plabel1 - filename, descriptive label of first parent
646 $child, $clabel - filename, descriptive label of child revision
676 $child, $clabel - filename, descriptive label of child revision
647 $parent2, $plabel2 - filename, descriptive label of second parent
677 $parent2, $plabel2 - filename, descriptive label of second parent
648 $root - repository root
678 $root - repository root
649 $parent is an alias for $parent1.
679 $parent is an alias for $parent1.
650
680
651 The extdiff extension will look in your [diff-tools] and [merge-tools]
681 The extdiff extension will look in your [diff-tools] and [merge-tools]
652 sections for diff tool arguments, when none are specified in [extdiff].
682 sections for diff tool arguments, when none are specified in [extdiff].
653
683
654 [extdiff]
684 [extdiff]
655 kdiff3 =
685 kdiff3 =
656
686
657 [diff-tools]
687 [diff-tools]
658 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
688 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
659
689
660 You can use -I/-X and list of file or directory names like normal 'hg diff'
690 You can use -I/-X and list of file or directory names like normal 'hg diff'
661 command. The extdiff extension makes snapshots of only needed files, so
691 command. The extdiff extension makes snapshots of only needed files, so
662 running the external diff program will actually be pretty fast (at least
692 running the external diff program will actually be pretty fast (at least
663 faster than having to compare the entire tree).
693 faster than having to compare the entire tree).
664
694
665 list of commands:
695 list of commands:
666
696
667 extdiff use external program to diff repository (or selected files)
697 extdiff use external program to diff repository (or selected files)
668
698
669 (use "hg help -v -e extdiff" to show built-in aliases and global options)
699 (use "hg help -v -e extdiff" to show built-in aliases and global options)
670
700
671
701
672
702
673
703
674
704
675
705
676
706
677
707
678
708
679
709
680
710
681
711
682
712
683
713
684
714
685
715
686 $ echo 'extdiff = !' >> $HGRCPATH
716 $ echo 'extdiff = !' >> $HGRCPATH
687
717
688 Test help topic with same name as extension
718 Test help topic with same name as extension
689
719
690 $ cat > multirevs.py <<EOF
720 $ cat > multirevs.py <<EOF
691 > from mercurial import cmdutil, commands
721 > from mercurial import cmdutil, commands
692 > cmdtable = {}
722 > cmdtable = {}
693 > command = cmdutil.command(cmdtable)
723 > command = cmdutil.command(cmdtable)
694 > """multirevs extension
724 > """multirevs extension
695 > Big multi-line module docstring."""
725 > Big multi-line module docstring."""
696 > @command('multirevs', [], 'ARG', norepo=True)
726 > @command('multirevs', [], 'ARG', norepo=True)
697 > def multirevs(ui, repo, arg, *args, **opts):
727 > def multirevs(ui, repo, arg, *args, **opts):
698 > """multirevs command"""
728 > """multirevs command"""
699 > pass
729 > pass
700 > EOF
730 > EOF
701 $ echo "multirevs = multirevs.py" >> $HGRCPATH
731 $ echo "multirevs = multirevs.py" >> $HGRCPATH
702
732
703 $ hg help multirevs
733 $ hg help multirevs
704 Specifying Multiple Revisions
734 Specifying Multiple Revisions
705 """""""""""""""""""""""""""""
735 """""""""""""""""""""""""""""
706
736
707 When Mercurial accepts more than one revision, they may be specified
737 When Mercurial accepts more than one revision, they may be specified
708 individually, or provided as a topologically continuous range, separated
738 individually, or provided as a topologically continuous range, separated
709 by the ":" character.
739 by the ":" character.
710
740
711 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
741 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
712 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
742 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
713 specified, it defaults to revision number 0. If END is not specified, it
743 specified, it defaults to revision number 0. If END is not specified, it
714 defaults to the tip. The range ":" thus means "all revisions".
744 defaults to the tip. The range ":" thus means "all revisions".
715
745
716 If BEGIN is greater than END, revisions are treated in reverse order.
746 If BEGIN is greater than END, revisions are treated in reverse order.
717
747
718 A range acts as a closed interval. This means that a range of 3:5 gives 3,
748 A range acts as a closed interval. This means that a range of 3:5 gives 3,
719 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
749 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
720
750
721 use "hg help -c multirevs" to see help for the multirevs command
751 use "hg help -c multirevs" to see help for the multirevs command
722
752
723
753
724
754
725
755
726
756
727
757
728 $ hg help -c multirevs
758 $ hg help -c multirevs
729 hg multirevs ARG
759 hg multirevs ARG
730
760
731 multirevs command
761 multirevs command
732
762
733 (some details hidden, use --verbose to show complete help)
763 (some details hidden, use --verbose to show complete help)
734
764
735
765
736
766
737 $ hg multirevs
767 $ hg multirevs
738 hg multirevs: invalid arguments
768 hg multirevs: invalid arguments
739 hg multirevs ARG
769 hg multirevs ARG
740
770
741 multirevs command
771 multirevs command
742
772
743 (use "hg multirevs -h" to show more help)
773 (use "hg multirevs -h" to show more help)
744 [255]
774 [255]
745
775
746
776
747
777
748 $ echo "multirevs = !" >> $HGRCPATH
778 $ echo "multirevs = !" >> $HGRCPATH
749
779
750 Issue811: Problem loading extensions twice (by site and by user)
780 Issue811: Problem loading extensions twice (by site and by user)
751
781
752 $ cat <<EOF >> $HGRCPATH
782 $ cat <<EOF >> $HGRCPATH
753 > mq =
783 > mq =
754 > strip =
784 > strip =
755 > hgext.mq =
785 > hgext.mq =
756 > hgext/mq =
786 > hgext/mq =
757 > EOF
787 > EOF
758
788
759 Show extensions:
789 Show extensions:
760 (note that mq force load strip, also checking it's not loaded twice)
790 (note that mq force load strip, also checking it's not loaded twice)
761
791
762 $ hg debugextensions
792 $ hg debugextensions
763 mq
793 mq
764 strip
794 strip
765
795
766 For extensions, which name matches one of its commands, help
796 For extensions, which name matches one of its commands, help
767 message should ask '-v -e' to get list of built-in aliases
797 message should ask '-v -e' to get list of built-in aliases
768 along with extension help itself
798 along with extension help itself
769
799
770 $ mkdir $TESTTMP/d
800 $ mkdir $TESTTMP/d
771 $ cat > $TESTTMP/d/dodo.py <<EOF
801 $ cat > $TESTTMP/d/dodo.py <<EOF
772 > """
802 > """
773 > This is an awesome 'dodo' extension. It does nothing and
803 > This is an awesome 'dodo' extension. It does nothing and
774 > writes 'Foo foo'
804 > writes 'Foo foo'
775 > """
805 > """
776 > from mercurial import cmdutil, commands
806 > from mercurial import cmdutil, commands
777 > cmdtable = {}
807 > cmdtable = {}
778 > command = cmdutil.command(cmdtable)
808 > command = cmdutil.command(cmdtable)
779 > @command('dodo', [], 'hg dodo')
809 > @command('dodo', [], 'hg dodo')
780 > def dodo(ui, *args, **kwargs):
810 > def dodo(ui, *args, **kwargs):
781 > """Does nothing"""
811 > """Does nothing"""
782 > ui.write("I do nothing. Yay\\n")
812 > ui.write("I do nothing. Yay\\n")
783 > @command('foofoo', [], 'hg foofoo')
813 > @command('foofoo', [], 'hg foofoo')
784 > def foofoo(ui, *args, **kwargs):
814 > def foofoo(ui, *args, **kwargs):
785 > """Writes 'Foo foo'"""
815 > """Writes 'Foo foo'"""
786 > ui.write("Foo foo\\n")
816 > ui.write("Foo foo\\n")
787 > EOF
817 > EOF
788 $ dodopath=$TESTTMP/d/dodo.py
818 $ dodopath=$TESTTMP/d/dodo.py
789
819
790 $ echo "dodo = $dodopath" >> $HGRCPATH
820 $ echo "dodo = $dodopath" >> $HGRCPATH
791
821
792 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
822 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
793 $ hg help -e dodo
823 $ hg help -e dodo
794 dodo extension -
824 dodo extension -
795
825
796 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
826 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
797
827
798 list of commands:
828 list of commands:
799
829
800 dodo Does nothing
830 dodo Does nothing
801 foofoo Writes 'Foo foo'
831 foofoo Writes 'Foo foo'
802
832
803 (use "hg help -v -e dodo" to show built-in aliases and global options)
833 (use "hg help -v -e dodo" to show built-in aliases and global options)
804
834
805 Make sure that '-v -e' prints list of built-in aliases along with
835 Make sure that '-v -e' prints list of built-in aliases along with
806 extension help itself
836 extension help itself
807 $ hg help -v -e dodo
837 $ hg help -v -e dodo
808 dodo extension -
838 dodo extension -
809
839
810 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
840 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
811
841
812 list of commands:
842 list of commands:
813
843
814 dodo Does nothing
844 dodo Does nothing
815 foofoo Writes 'Foo foo'
845 foofoo Writes 'Foo foo'
816
846
817 global options ([+] can be repeated):
847 global options ([+] can be repeated):
818
848
819 -R --repository REPO repository root directory or name of overlay bundle
849 -R --repository REPO repository root directory or name of overlay bundle
820 file
850 file
821 --cwd DIR change working directory
851 --cwd DIR change working directory
822 -y --noninteractive do not prompt, automatically pick the first choice for
852 -y --noninteractive do not prompt, automatically pick the first choice for
823 all prompts
853 all prompts
824 -q --quiet suppress output
854 -q --quiet suppress output
825 -v --verbose enable additional output
855 -v --verbose enable additional output
826 --config CONFIG [+] set/override config option (use 'section.name=value')
856 --config CONFIG [+] set/override config option (use 'section.name=value')
827 --debug enable debugging output
857 --debug enable debugging output
828 --debugger start debugger
858 --debugger start debugger
829 --encoding ENCODE set the charset encoding (default: ascii)
859 --encoding ENCODE set the charset encoding (default: ascii)
830 --encodingmode MODE set the charset encoding mode (default: strict)
860 --encodingmode MODE set the charset encoding mode (default: strict)
831 --traceback always print a traceback on exception
861 --traceback always print a traceback on exception
832 --time time how long the command takes
862 --time time how long the command takes
833 --profile print command execution profile
863 --profile print command execution profile
834 --version output version information and exit
864 --version output version information and exit
835 -h --help display help and exit
865 -h --help display help and exit
836 --hidden consider hidden changesets
866 --hidden consider hidden changesets
837
867
838 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
868 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
839 $ hg help -v dodo
869 $ hg help -v dodo
840 hg dodo
870 hg dodo
841
871
842 Does nothing
872 Does nothing
843
873
844 (use "hg help -e dodo" to show help for the dodo extension)
874 (use "hg help -e dodo" to show help for the dodo extension)
845
875
846 options:
876 options:
847
877
848 --mq operate on patch repository
878 --mq operate on patch repository
849
879
850 global options ([+] can be repeated):
880 global options ([+] can be repeated):
851
881
852 -R --repository REPO repository root directory or name of overlay bundle
882 -R --repository REPO repository root directory or name of overlay bundle
853 file
883 file
854 --cwd DIR change working directory
884 --cwd DIR change working directory
855 -y --noninteractive do not prompt, automatically pick the first choice for
885 -y --noninteractive do not prompt, automatically pick the first choice for
856 all prompts
886 all prompts
857 -q --quiet suppress output
887 -q --quiet suppress output
858 -v --verbose enable additional output
888 -v --verbose enable additional output
859 --config CONFIG [+] set/override config option (use 'section.name=value')
889 --config CONFIG [+] set/override config option (use 'section.name=value')
860 --debug enable debugging output
890 --debug enable debugging output
861 --debugger start debugger
891 --debugger start debugger
862 --encoding ENCODE set the charset encoding (default: ascii)
892 --encoding ENCODE set the charset encoding (default: ascii)
863 --encodingmode MODE set the charset encoding mode (default: strict)
893 --encodingmode MODE set the charset encoding mode (default: strict)
864 --traceback always print a traceback on exception
894 --traceback always print a traceback on exception
865 --time time how long the command takes
895 --time time how long the command takes
866 --profile print command execution profile
896 --profile print command execution profile
867 --version output version information and exit
897 --version output version information and exit
868 -h --help display help and exit
898 -h --help display help and exit
869 --hidden consider hidden changesets
899 --hidden consider hidden changesets
870
900
871 In case when extension name doesn't match any of its commands,
901 In case when extension name doesn't match any of its commands,
872 help message should ask for '-v' to get list of built-in aliases
902 help message should ask for '-v' to get list of built-in aliases
873 along with extension help
903 along with extension help
874 $ cat > $TESTTMP/d/dudu.py <<EOF
904 $ cat > $TESTTMP/d/dudu.py <<EOF
875 > """
905 > """
876 > This is an awesome 'dudu' extension. It does something and
906 > This is an awesome 'dudu' extension. It does something and
877 > also writes 'Beep beep'
907 > also writes 'Beep beep'
878 > """
908 > """
879 > from mercurial import cmdutil, commands
909 > from mercurial import cmdutil, commands
880 > cmdtable = {}
910 > cmdtable = {}
881 > command = cmdutil.command(cmdtable)
911 > command = cmdutil.command(cmdtable)
882 > @command('something', [], 'hg something')
912 > @command('something', [], 'hg something')
883 > def something(ui, *args, **kwargs):
913 > def something(ui, *args, **kwargs):
884 > """Does something"""
914 > """Does something"""
885 > ui.write("I do something. Yaaay\\n")
915 > ui.write("I do something. Yaaay\\n")
886 > @command('beep', [], 'hg beep')
916 > @command('beep', [], 'hg beep')
887 > def beep(ui, *args, **kwargs):
917 > def beep(ui, *args, **kwargs):
888 > """Writes 'Beep beep'"""
918 > """Writes 'Beep beep'"""
889 > ui.write("Beep beep\\n")
919 > ui.write("Beep beep\\n")
890 > EOF
920 > EOF
891 $ dudupath=$TESTTMP/d/dudu.py
921 $ dudupath=$TESTTMP/d/dudu.py
892
922
893 $ echo "dudu = $dudupath" >> $HGRCPATH
923 $ echo "dudu = $dudupath" >> $HGRCPATH
894
924
895 $ hg help -e dudu
925 $ hg help -e dudu
896 dudu extension -
926 dudu extension -
897
927
898 This is an awesome 'dudu' extension. It does something and also writes 'Beep
928 This is an awesome 'dudu' extension. It does something and also writes 'Beep
899 beep'
929 beep'
900
930
901 list of commands:
931 list of commands:
902
932
903 beep Writes 'Beep beep'
933 beep Writes 'Beep beep'
904 something Does something
934 something Does something
905
935
906 (use "hg help -v dudu" to show built-in aliases and global options)
936 (use "hg help -v dudu" to show built-in aliases and global options)
907
937
908 In case when extension name doesn't match any of its commands,
938 In case when extension name doesn't match any of its commands,
909 help options '-v' and '-v -e' should be equivalent
939 help options '-v' and '-v -e' should be equivalent
910 $ hg help -v dudu
940 $ hg help -v dudu
911 dudu extension -
941 dudu extension -
912
942
913 This is an awesome 'dudu' extension. It does something and also writes 'Beep
943 This is an awesome 'dudu' extension. It does something and also writes 'Beep
914 beep'
944 beep'
915
945
916 list of commands:
946 list of commands:
917
947
918 beep Writes 'Beep beep'
948 beep Writes 'Beep beep'
919 something Does something
949 something Does something
920
950
921 global options ([+] can be repeated):
951 global options ([+] can be repeated):
922
952
923 -R --repository REPO repository root directory or name of overlay bundle
953 -R --repository REPO repository root directory or name of overlay bundle
924 file
954 file
925 --cwd DIR change working directory
955 --cwd DIR change working directory
926 -y --noninteractive do not prompt, automatically pick the first choice for
956 -y --noninteractive do not prompt, automatically pick the first choice for
927 all prompts
957 all prompts
928 -q --quiet suppress output
958 -q --quiet suppress output
929 -v --verbose enable additional output
959 -v --verbose enable additional output
930 --config CONFIG [+] set/override config option (use 'section.name=value')
960 --config CONFIG [+] set/override config option (use 'section.name=value')
931 --debug enable debugging output
961 --debug enable debugging output
932 --debugger start debugger
962 --debugger start debugger
933 --encoding ENCODE set the charset encoding (default: ascii)
963 --encoding ENCODE set the charset encoding (default: ascii)
934 --encodingmode MODE set the charset encoding mode (default: strict)
964 --encodingmode MODE set the charset encoding mode (default: strict)
935 --traceback always print a traceback on exception
965 --traceback always print a traceback on exception
936 --time time how long the command takes
966 --time time how long the command takes
937 --profile print command execution profile
967 --profile print command execution profile
938 --version output version information and exit
968 --version output version information and exit
939 -h --help display help and exit
969 -h --help display help and exit
940 --hidden consider hidden changesets
970 --hidden consider hidden changesets
941
971
942 $ hg help -v -e dudu
972 $ hg help -v -e dudu
943 dudu extension -
973 dudu extension -
944
974
945 This is an awesome 'dudu' extension. It does something and also writes 'Beep
975 This is an awesome 'dudu' extension. It does something and also writes 'Beep
946 beep'
976 beep'
947
977
948 list of commands:
978 list of commands:
949
979
950 beep Writes 'Beep beep'
980 beep Writes 'Beep beep'
951 something Does something
981 something Does something
952
982
953 global options ([+] can be repeated):
983 global options ([+] can be repeated):
954
984
955 -R --repository REPO repository root directory or name of overlay bundle
985 -R --repository REPO repository root directory or name of overlay bundle
956 file
986 file
957 --cwd DIR change working directory
987 --cwd DIR change working directory
958 -y --noninteractive do not prompt, automatically pick the first choice for
988 -y --noninteractive do not prompt, automatically pick the first choice for
959 all prompts
989 all prompts
960 -q --quiet suppress output
990 -q --quiet suppress output
961 -v --verbose enable additional output
991 -v --verbose enable additional output
962 --config CONFIG [+] set/override config option (use 'section.name=value')
992 --config CONFIG [+] set/override config option (use 'section.name=value')
963 --debug enable debugging output
993 --debug enable debugging output
964 --debugger start debugger
994 --debugger start debugger
965 --encoding ENCODE set the charset encoding (default: ascii)
995 --encoding ENCODE set the charset encoding (default: ascii)
966 --encodingmode MODE set the charset encoding mode (default: strict)
996 --encodingmode MODE set the charset encoding mode (default: strict)
967 --traceback always print a traceback on exception
997 --traceback always print a traceback on exception
968 --time time how long the command takes
998 --time time how long the command takes
969 --profile print command execution profile
999 --profile print command execution profile
970 --version output version information and exit
1000 --version output version information and exit
971 -h --help display help and exit
1001 -h --help display help and exit
972 --hidden consider hidden changesets
1002 --hidden consider hidden changesets
973
1003
974 Disabled extension commands:
1004 Disabled extension commands:
975
1005
976 $ ORGHGRCPATH=$HGRCPATH
1006 $ ORGHGRCPATH=$HGRCPATH
977 $ HGRCPATH=
1007 $ HGRCPATH=
978 $ export HGRCPATH
1008 $ export HGRCPATH
979 $ hg help email
1009 $ hg help email
980 'email' is provided by the following extension:
1010 'email' is provided by the following extension:
981
1011
982 patchbomb command to send changesets as (a series of) patch emails
1012 patchbomb command to send changesets as (a series of) patch emails
983
1013
984 (use "hg help extensions" for information on enabling extensions)
1014 (use "hg help extensions" for information on enabling extensions)
985
1015
986
1016
987 $ hg qdel
1017 $ hg qdel
988 hg: unknown command 'qdel'
1018 hg: unknown command 'qdel'
989 'qdelete' is provided by the following extension:
1019 'qdelete' is provided by the following extension:
990
1020
991 mq manage a stack of patches
1021 mq manage a stack of patches
992
1022
993 (use "hg help extensions" for information on enabling extensions)
1023 (use "hg help extensions" for information on enabling extensions)
994 [255]
1024 [255]
995
1025
996
1026
997 $ hg churn
1027 $ hg churn
998 hg: unknown command 'churn'
1028 hg: unknown command 'churn'
999 'churn' is provided by the following extension:
1029 'churn' is provided by the following extension:
1000
1030
1001 churn command to display statistics about repository history
1031 churn command to display statistics about repository history
1002
1032
1003 (use "hg help extensions" for information on enabling extensions)
1033 (use "hg help extensions" for information on enabling extensions)
1004 [255]
1034 [255]
1005
1035
1006
1036
1007
1037
1008 Disabled extensions:
1038 Disabled extensions:
1009
1039
1010 $ hg help churn
1040 $ hg help churn
1011 churn extension - command to display statistics about repository history
1041 churn extension - command to display statistics about repository history
1012
1042
1013 (use "hg help extensions" for information on enabling extensions)
1043 (use "hg help extensions" for information on enabling extensions)
1014
1044
1015 $ hg help patchbomb
1045 $ hg help patchbomb
1016 patchbomb extension - command to send changesets as (a series of) patch emails
1046 patchbomb extension - command to send changesets as (a series of) patch emails
1017
1047
1018 (use "hg help extensions" for information on enabling extensions)
1048 (use "hg help extensions" for information on enabling extensions)
1019
1049
1020
1050
1021 Broken disabled extension and command:
1051 Broken disabled extension and command:
1022
1052
1023 $ mkdir hgext
1053 $ mkdir hgext
1024 $ echo > hgext/__init__.py
1054 $ echo > hgext/__init__.py
1025 $ cat > hgext/broken.py <<EOF
1055 $ cat > hgext/broken.py <<EOF
1026 > "broken extension'
1056 > "broken extension'
1027 > EOF
1057 > EOF
1028 $ cat > path.py <<EOF
1058 $ cat > path.py <<EOF
1029 > import os, sys
1059 > import os, sys
1030 > sys.path.insert(0, os.environ['HGEXTPATH'])
1060 > sys.path.insert(0, os.environ['HGEXTPATH'])
1031 > EOF
1061 > EOF
1032 $ HGEXTPATH=`pwd`
1062 $ HGEXTPATH=`pwd`
1033 $ export HGEXTPATH
1063 $ export HGEXTPATH
1034
1064
1035 $ hg --config extensions.path=./path.py help broken
1065 $ hg --config extensions.path=./path.py help broken
1036 broken extension - (no help text available)
1066 broken extension - (no help text available)
1037
1067
1038 (use "hg help extensions" for information on enabling extensions)
1068 (use "hg help extensions" for information on enabling extensions)
1039
1069
1040
1070
1041 $ cat > hgext/forest.py <<EOF
1071 $ cat > hgext/forest.py <<EOF
1042 > cmdtable = None
1072 > cmdtable = None
1043 > EOF
1073 > EOF
1044 $ hg --config extensions.path=./path.py help foo > /dev/null
1074 $ hg --config extensions.path=./path.py help foo > /dev/null
1045 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
1075 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
1046 abort: no such help topic: foo
1076 abort: no such help topic: foo
1047 (try "hg help --keyword foo")
1077 (try "hg help --keyword foo")
1048 [255]
1078 [255]
1049
1079
1050 $ cat > throw.py <<EOF
1080 $ cat > throw.py <<EOF
1051 > from mercurial import cmdutil, commands, util
1081 > from mercurial import cmdutil, commands, util
1052 > cmdtable = {}
1082 > cmdtable = {}
1053 > command = cmdutil.command(cmdtable)
1083 > command = cmdutil.command(cmdtable)
1054 > class Bogon(Exception): pass
1084 > class Bogon(Exception): pass
1055 > @command('throw', [], 'hg throw', norepo=True)
1085 > @command('throw', [], 'hg throw', norepo=True)
1056 > def throw(ui, **opts):
1086 > def throw(ui, **opts):
1057 > """throws an exception"""
1087 > """throws an exception"""
1058 > raise Bogon()
1088 > raise Bogon()
1059 > EOF
1089 > EOF
1060
1090
1061 No declared supported version, extension complains:
1091 No declared supported version, extension complains:
1062 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1092 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1063 ** Unknown exception encountered with possibly-broken third-party extension throw
1093 ** Unknown exception encountered with possibly-broken third-party extension throw
1064 ** which supports versions unknown of Mercurial.
1094 ** which supports versions unknown of Mercurial.
1065 ** Please disable throw and try your action again.
1095 ** Please disable throw and try your action again.
1066 ** If that fixes the bug please report it to the extension author.
1096 ** If that fixes the bug please report it to the extension author.
1067 ** Python * (glob)
1097 ** Python * (glob)
1068 ** Mercurial Distributed SCM * (glob)
1098 ** Mercurial Distributed SCM * (glob)
1069 ** Extensions loaded: throw
1099 ** Extensions loaded: throw
1070
1100
1071 empty declaration of supported version, extension complains:
1101 empty declaration of supported version, extension complains:
1072 $ echo "testedwith = ''" >> throw.py
1102 $ echo "testedwith = ''" >> throw.py
1073 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1103 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1074 ** Unknown exception encountered with possibly-broken third-party extension throw
1104 ** Unknown exception encountered with possibly-broken third-party extension throw
1075 ** which supports versions unknown of Mercurial.
1105 ** which supports versions unknown of Mercurial.
1076 ** Please disable throw and try your action again.
1106 ** Please disable throw and try your action again.
1077 ** If that fixes the bug please report it to the extension author.
1107 ** If that fixes the bug please report it to the extension author.
1078 ** Python * (glob)
1108 ** Python * (glob)
1079 ** Mercurial Distributed SCM (*) (glob)
1109 ** Mercurial Distributed SCM (*) (glob)
1080 ** Extensions loaded: throw
1110 ** Extensions loaded: throw
1081
1111
1082 If the extension specifies a buglink, show that:
1112 If the extension specifies a buglink, show that:
1083 $ echo 'buglink = "http://example.com/bts"' >> throw.py
1113 $ echo 'buglink = "http://example.com/bts"' >> throw.py
1084 $ rm -f throw.pyc throw.pyo
1114 $ rm -f throw.pyc throw.pyo
1085 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1115 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1086 ** Unknown exception encountered with possibly-broken third-party extension throw
1116 ** Unknown exception encountered with possibly-broken third-party extension throw
1087 ** which supports versions unknown of Mercurial.
1117 ** which supports versions unknown of Mercurial.
1088 ** Please disable throw and try your action again.
1118 ** Please disable throw and try your action again.
1089 ** If that fixes the bug please report it to http://example.com/bts
1119 ** If that fixes the bug please report it to http://example.com/bts
1090 ** Python * (glob)
1120 ** Python * (glob)
1091 ** Mercurial Distributed SCM (*) (glob)
1121 ** Mercurial Distributed SCM (*) (glob)
1092 ** Extensions loaded: throw
1122 ** Extensions loaded: throw
1093
1123
1094 If the extensions declare outdated versions, accuse the older extension first:
1124 If the extensions declare outdated versions, accuse the older extension first:
1095 $ echo "from mercurial import util" >> older.py
1125 $ echo "from mercurial import util" >> older.py
1096 $ echo "util.version = lambda:'2.2'" >> older.py
1126 $ echo "util.version = lambda:'2.2'" >> older.py
1097 $ echo "testedwith = '1.9.3'" >> older.py
1127 $ echo "testedwith = '1.9.3'" >> older.py
1098 $ echo "testedwith = '2.1.1'" >> throw.py
1128 $ echo "testedwith = '2.1.1'" >> throw.py
1099 $ rm -f throw.pyc throw.pyo
1129 $ rm -f throw.pyc throw.pyo
1100 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1130 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1101 > throw 2>&1 | egrep '^\*\*'
1131 > throw 2>&1 | egrep '^\*\*'
1102 ** Unknown exception encountered with possibly-broken third-party extension older
1132 ** Unknown exception encountered with possibly-broken third-party extension older
1103 ** which supports versions 1.9 of Mercurial.
1133 ** which supports versions 1.9 of Mercurial.
1104 ** Please disable older and try your action again.
1134 ** Please disable older and try your action again.
1105 ** If that fixes the bug please report it to the extension author.
1135 ** If that fixes the bug please report it to the extension author.
1106 ** Python * (glob)
1136 ** Python * (glob)
1107 ** Mercurial Distributed SCM (version 2.2)
1137 ** Mercurial Distributed SCM (version 2.2)
1108 ** Extensions loaded: throw, older
1138 ** Extensions loaded: throw, older
1109
1139
1110 One extension only tested with older, one only with newer versions:
1140 One extension only tested with older, one only with newer versions:
1111 $ echo "util.version = lambda:'2.1'" >> older.py
1141 $ echo "util.version = lambda:'2.1'" >> older.py
1112 $ rm -f older.pyc older.pyo
1142 $ rm -f older.pyc older.pyo
1113 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1143 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1114 > throw 2>&1 | egrep '^\*\*'
1144 > throw 2>&1 | egrep '^\*\*'
1115 ** Unknown exception encountered with possibly-broken third-party extension older
1145 ** Unknown exception encountered with possibly-broken third-party extension older
1116 ** which supports versions 1.9 of Mercurial.
1146 ** which supports versions 1.9 of Mercurial.
1117 ** Please disable older and try your action again.
1147 ** Please disable older and try your action again.
1118 ** If that fixes the bug please report it to the extension author.
1148 ** If that fixes the bug please report it to the extension author.
1119 ** Python * (glob)
1149 ** Python * (glob)
1120 ** Mercurial Distributed SCM (version 2.1)
1150 ** Mercurial Distributed SCM (version 2.1)
1121 ** Extensions loaded: throw, older
1151 ** Extensions loaded: throw, older
1122
1152
1123 Older extension is tested with current version, the other only with newer:
1153 Older extension is tested with current version, the other only with newer:
1124 $ echo "util.version = lambda:'1.9.3'" >> older.py
1154 $ echo "util.version = lambda:'1.9.3'" >> older.py
1125 $ rm -f older.pyc older.pyo
1155 $ rm -f older.pyc older.pyo
1126 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1156 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1127 > throw 2>&1 | egrep '^\*\*'
1157 > throw 2>&1 | egrep '^\*\*'
1128 ** Unknown exception encountered with possibly-broken third-party extension throw
1158 ** Unknown exception encountered with possibly-broken third-party extension throw
1129 ** which supports versions 2.1 of Mercurial.
1159 ** which supports versions 2.1 of Mercurial.
1130 ** Please disable throw and try your action again.
1160 ** Please disable throw and try your action again.
1131 ** If that fixes the bug please report it to http://example.com/bts
1161 ** If that fixes the bug please report it to http://example.com/bts
1132 ** Python * (glob)
1162 ** Python * (glob)
1133 ** Mercurial Distributed SCM (version 1.9.3)
1163 ** Mercurial Distributed SCM (version 1.9.3)
1134 ** Extensions loaded: throw, older
1164 ** Extensions loaded: throw, older
1135
1165
1136 Ability to point to a different point
1166 Ability to point to a different point
1137 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1167 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1138 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
1168 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
1139 ** unknown exception encountered, please report by visiting
1169 ** unknown exception encountered, please report by visiting
1140 ** Your Local Goat Lenders
1170 ** Your Local Goat Lenders
1141 ** Python * (glob)
1171 ** Python * (glob)
1142 ** Mercurial Distributed SCM (*) (glob)
1172 ** Mercurial Distributed SCM (*) (glob)
1143 ** Extensions loaded: throw, older
1173 ** Extensions loaded: throw, older
1144
1174
1145 Declare the version as supporting this hg version, show regular bts link:
1175 Declare the version as supporting this hg version, show regular bts link:
1146 $ hgver=`hg debuginstall -T '{hgver}'`
1176 $ hgver=`hg debuginstall -T '{hgver}'`
1147 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
1177 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
1148 $ if [ -z "$hgver" ]; then
1178 $ if [ -z "$hgver" ]; then
1149 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
1179 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
1150 > fi
1180 > fi
1151 $ rm -f throw.pyc throw.pyo
1181 $ rm -f throw.pyc throw.pyo
1152 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1182 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1153 ** unknown exception encountered, please report by visiting
1183 ** unknown exception encountered, please report by visiting
1154 ** https://mercurial-scm.org/wiki/BugTracker
1184 ** https://mercurial-scm.org/wiki/BugTracker
1155 ** Python * (glob)
1185 ** Python * (glob)
1156 ** Mercurial Distributed SCM (*) (glob)
1186 ** Mercurial Distributed SCM (*) (glob)
1157 ** Extensions loaded: throw
1187 ** Extensions loaded: throw
1158
1188
1159 Patch version is ignored during compatibility check
1189 Patch version is ignored during compatibility check
1160 $ echo "testedwith = '3.2'" >> throw.py
1190 $ echo "testedwith = '3.2'" >> throw.py
1161 $ echo "util.version = lambda:'3.2.2'" >> throw.py
1191 $ echo "util.version = lambda:'3.2.2'" >> throw.py
1162 $ rm -f throw.pyc throw.pyo
1192 $ rm -f throw.pyc throw.pyo
1163 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1193 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1164 ** unknown exception encountered, please report by visiting
1194 ** unknown exception encountered, please report by visiting
1165 ** https://mercurial-scm.org/wiki/BugTracker
1195 ** https://mercurial-scm.org/wiki/BugTracker
1166 ** Python * (glob)
1196 ** Python * (glob)
1167 ** Mercurial Distributed SCM (*) (glob)
1197 ** Mercurial Distributed SCM (*) (glob)
1168 ** Extensions loaded: throw
1198 ** Extensions loaded: throw
1169
1199
1170 Test version number support in 'hg version':
1200 Test version number support in 'hg version':
1171 $ echo '__version__ = (1, 2, 3)' >> throw.py
1201 $ echo '__version__ = (1, 2, 3)' >> throw.py
1172 $ rm -f throw.pyc throw.pyo
1202 $ rm -f throw.pyc throw.pyo
1173 $ hg version -v
1203 $ hg version -v
1174 Mercurial Distributed SCM (version *) (glob)
1204 Mercurial Distributed SCM (version *) (glob)
1175 (see https://mercurial-scm.org for more information)
1205 (see https://mercurial-scm.org for more information)
1176
1206
1177 Copyright (C) 2005-* Matt Mackall and others (glob)
1207 Copyright (C) 2005-* Matt Mackall and others (glob)
1178 This is free software; see the source for copying conditions. There is NO
1208 This is free software; see the source for copying conditions. There is NO
1179 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1209 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1180
1210
1181 Enabled extensions:
1211 Enabled extensions:
1182
1212
1183
1213
1184 $ hg version -v --config extensions.throw=throw.py
1214 $ hg version -v --config extensions.throw=throw.py
1185 Mercurial Distributed SCM (version *) (glob)
1215 Mercurial Distributed SCM (version *) (glob)
1186 (see https://mercurial-scm.org for more information)
1216 (see https://mercurial-scm.org for more information)
1187
1217
1188 Copyright (C) 2005-* Matt Mackall and others (glob)
1218 Copyright (C) 2005-* Matt Mackall and others (glob)
1189 This is free software; see the source for copying conditions. There is NO
1219 This is free software; see the source for copying conditions. There is NO
1190 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1220 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1191
1221
1192 Enabled extensions:
1222 Enabled extensions:
1193
1223
1194 throw external 1.2.3
1224 throw external 1.2.3
1195 $ echo 'getversion = lambda: "1.twentythree"' >> throw.py
1225 $ echo 'getversion = lambda: "1.twentythree"' >> throw.py
1196 $ rm -f throw.pyc throw.pyo
1226 $ rm -f throw.pyc throw.pyo
1197 $ hg version -v --config extensions.throw=throw.py
1227 $ hg version -v --config extensions.throw=throw.py
1198 Mercurial Distributed SCM (version *) (glob)
1228 Mercurial Distributed SCM (version *) (glob)
1199 (see https://mercurial-scm.org for more information)
1229 (see https://mercurial-scm.org for more information)
1200
1230
1201 Copyright (C) 2005-* Matt Mackall and others (glob)
1231 Copyright (C) 2005-* Matt Mackall and others (glob)
1202 This is free software; see the source for copying conditions. There is NO
1232 This is free software; see the source for copying conditions. There is NO
1203 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1233 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1204
1234
1205 Enabled extensions:
1235 Enabled extensions:
1206
1236
1207 throw external 1.twentythree
1237 throw external 1.twentythree
1208
1238
1209 Refuse to load extensions with minimum version requirements
1239 Refuse to load extensions with minimum version requirements
1210
1240
1211 $ cat > minversion1.py << EOF
1241 $ cat > minversion1.py << EOF
1212 > from mercurial import util
1242 > from mercurial import util
1213 > util.version = lambda: '3.5.2'
1243 > util.version = lambda: '3.5.2'
1214 > minimumhgversion = '3.6'
1244 > minimumhgversion = '3.6'
1215 > EOF
1245 > EOF
1216 $ hg --config extensions.minversion=minversion1.py version
1246 $ hg --config extensions.minversion=minversion1.py version
1217 (third party extension minversion requires version 3.6 or newer of Mercurial; disabling)
1247 (third party extension minversion requires version 3.6 or newer of Mercurial; disabling)
1218 Mercurial Distributed SCM (version 3.5.2)
1248 Mercurial Distributed SCM (version 3.5.2)
1219 (see https://mercurial-scm.org for more information)
1249 (see https://mercurial-scm.org for more information)
1220
1250
1221 Copyright (C) 2005-* Matt Mackall and others (glob)
1251 Copyright (C) 2005-* Matt Mackall and others (glob)
1222 This is free software; see the source for copying conditions. There is NO
1252 This is free software; see the source for copying conditions. There is NO
1223 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1253 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1224
1254
1225 $ cat > minversion2.py << EOF
1255 $ cat > minversion2.py << EOF
1226 > from mercurial import util
1256 > from mercurial import util
1227 > util.version = lambda: '3.6'
1257 > util.version = lambda: '3.6'
1228 > minimumhgversion = '3.7'
1258 > minimumhgversion = '3.7'
1229 > EOF
1259 > EOF
1230 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1260 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1231 (third party extension minversion requires version 3.7 or newer of Mercurial; disabling)
1261 (third party extension minversion requires version 3.7 or newer of Mercurial; disabling)
1232
1262
1233 Can load version that is only off by point release
1263 Can load version that is only off by point release
1234
1264
1235 $ cat > minversion2.py << EOF
1265 $ cat > minversion2.py << EOF
1236 > from mercurial import util
1266 > from mercurial import util
1237 > util.version = lambda: '3.6.1'
1267 > util.version = lambda: '3.6.1'
1238 > minimumhgversion = '3.6'
1268 > minimumhgversion = '3.6'
1239 > EOF
1269 > EOF
1240 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1270 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1241 [1]
1271 [1]
1242
1272
1243 Can load minimum version identical to current
1273 Can load minimum version identical to current
1244
1274
1245 $ cat > minversion3.py << EOF
1275 $ cat > minversion3.py << EOF
1246 > from mercurial import util
1276 > from mercurial import util
1247 > util.version = lambda: '3.5'
1277 > util.version = lambda: '3.5'
1248 > minimumhgversion = '3.5'
1278 > minimumhgversion = '3.5'
1249 > EOF
1279 > EOF
1250 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1280 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1251 [1]
1281 [1]
1252
1282
1253 Restore HGRCPATH
1283 Restore HGRCPATH
1254
1284
1255 $ HGRCPATH=$ORGHGRCPATH
1285 $ HGRCPATH=$ORGHGRCPATH
1256 $ export HGRCPATH
1286 $ export HGRCPATH
1257
1287
1258 Commands handling multiple repositories at a time should invoke only
1288 Commands handling multiple repositories at a time should invoke only
1259 "reposetup()" of extensions enabling in the target repository.
1289 "reposetup()" of extensions enabling in the target repository.
1260
1290
1261 $ mkdir reposetup-test
1291 $ mkdir reposetup-test
1262 $ cd reposetup-test
1292 $ cd reposetup-test
1263
1293
1264 $ cat > $TESTTMP/reposetuptest.py <<EOF
1294 $ cat > $TESTTMP/reposetuptest.py <<EOF
1265 > from mercurial import extensions
1295 > from mercurial import extensions
1266 > def reposetup(ui, repo):
1296 > def reposetup(ui, repo):
1267 > ui.write('reposetup() for %s\n' % (repo.root))
1297 > ui.write('reposetup() for %s\n' % (repo.root))
1268 > ui.flush()
1298 > ui.flush()
1269 > EOF
1299 > EOF
1270 $ hg init src
1300 $ hg init src
1271 $ echo a > src/a
1301 $ echo a > src/a
1272 $ hg -R src commit -Am '#0 at src/a'
1302 $ hg -R src commit -Am '#0 at src/a'
1273 adding a
1303 adding a
1274 $ echo '[extensions]' >> src/.hg/hgrc
1304 $ echo '[extensions]' >> src/.hg/hgrc
1275 $ echo '# enable extension locally' >> src/.hg/hgrc
1305 $ echo '# enable extension locally' >> src/.hg/hgrc
1276 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1306 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1277 $ hg -R src status
1307 $ hg -R src status
1278 reposetup() for $TESTTMP/reposetup-test/src (glob)
1308 reposetup() for $TESTTMP/reposetup-test/src (glob)
1279
1309
1280 $ hg clone -U src clone-dst1
1310 $ hg clone -U src clone-dst1
1281 reposetup() for $TESTTMP/reposetup-test/src (glob)
1311 reposetup() for $TESTTMP/reposetup-test/src (glob)
1282 $ hg init push-dst1
1312 $ hg init push-dst1
1283 $ hg -q -R src push push-dst1
1313 $ hg -q -R src push push-dst1
1284 reposetup() for $TESTTMP/reposetup-test/src (glob)
1314 reposetup() for $TESTTMP/reposetup-test/src (glob)
1285 $ hg init pull-src1
1315 $ hg init pull-src1
1286 $ hg -q -R pull-src1 pull src
1316 $ hg -q -R pull-src1 pull src
1287 reposetup() for $TESTTMP/reposetup-test/src (glob)
1317 reposetup() for $TESTTMP/reposetup-test/src (glob)
1288
1318
1289 $ cat <<EOF >> $HGRCPATH
1319 $ cat <<EOF >> $HGRCPATH
1290 > [extensions]
1320 > [extensions]
1291 > # disable extension globally and explicitly
1321 > # disable extension globally and explicitly
1292 > reposetuptest = !
1322 > reposetuptest = !
1293 > EOF
1323 > EOF
1294 $ hg clone -U src clone-dst2
1324 $ hg clone -U src clone-dst2
1295 reposetup() for $TESTTMP/reposetup-test/src (glob)
1325 reposetup() for $TESTTMP/reposetup-test/src (glob)
1296 $ hg init push-dst2
1326 $ hg init push-dst2
1297 $ hg -q -R src push push-dst2
1327 $ hg -q -R src push push-dst2
1298 reposetup() for $TESTTMP/reposetup-test/src (glob)
1328 reposetup() for $TESTTMP/reposetup-test/src (glob)
1299 $ hg init pull-src2
1329 $ hg init pull-src2
1300 $ hg -q -R pull-src2 pull src
1330 $ hg -q -R pull-src2 pull src
1301 reposetup() for $TESTTMP/reposetup-test/src (glob)
1331 reposetup() for $TESTTMP/reposetup-test/src (glob)
1302
1332
1303 $ cat <<EOF >> $HGRCPATH
1333 $ cat <<EOF >> $HGRCPATH
1304 > [extensions]
1334 > [extensions]
1305 > # enable extension globally
1335 > # enable extension globally
1306 > reposetuptest = $TESTTMP/reposetuptest.py
1336 > reposetuptest = $TESTTMP/reposetuptest.py
1307 > EOF
1337 > EOF
1308 $ hg clone -U src clone-dst3
1338 $ hg clone -U src clone-dst3
1309 reposetup() for $TESTTMP/reposetup-test/src (glob)
1339 reposetup() for $TESTTMP/reposetup-test/src (glob)
1310 reposetup() for $TESTTMP/reposetup-test/clone-dst3 (glob)
1340 reposetup() for $TESTTMP/reposetup-test/clone-dst3 (glob)
1311 $ hg init push-dst3
1341 $ hg init push-dst3
1312 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1342 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1313 $ hg -q -R src push push-dst3
1343 $ hg -q -R src push push-dst3
1314 reposetup() for $TESTTMP/reposetup-test/src (glob)
1344 reposetup() for $TESTTMP/reposetup-test/src (glob)
1315 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1345 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1316 $ hg init pull-src3
1346 $ hg init pull-src3
1317 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1347 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1318 $ hg -q -R pull-src3 pull src
1348 $ hg -q -R pull-src3 pull src
1319 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1349 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1320 reposetup() for $TESTTMP/reposetup-test/src (glob)
1350 reposetup() for $TESTTMP/reposetup-test/src (glob)
1321
1351
1322 $ echo '[extensions]' >> src/.hg/hgrc
1352 $ echo '[extensions]' >> src/.hg/hgrc
1323 $ echo '# disable extension locally' >> src/.hg/hgrc
1353 $ echo '# disable extension locally' >> src/.hg/hgrc
1324 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1354 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1325 $ hg clone -U src clone-dst4
1355 $ hg clone -U src clone-dst4
1326 reposetup() for $TESTTMP/reposetup-test/clone-dst4 (glob)
1356 reposetup() for $TESTTMP/reposetup-test/clone-dst4 (glob)
1327 $ hg init push-dst4
1357 $ hg init push-dst4
1328 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1358 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1329 $ hg -q -R src push push-dst4
1359 $ hg -q -R src push push-dst4
1330 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1360 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1331 $ hg init pull-src4
1361 $ hg init pull-src4
1332 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1362 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1333 $ hg -q -R pull-src4 pull src
1363 $ hg -q -R pull-src4 pull src
1334 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1364 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1335
1365
1336 disabling in command line overlays with all configuration
1366 disabling in command line overlays with all configuration
1337 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1367 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1338 $ hg --config extensions.reposetuptest=! init push-dst5
1368 $ hg --config extensions.reposetuptest=! init push-dst5
1339 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1369 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1340 $ hg --config extensions.reposetuptest=! init pull-src5
1370 $ hg --config extensions.reposetuptest=! init pull-src5
1341 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1371 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1342
1372
1343 $ cat <<EOF >> $HGRCPATH
1373 $ cat <<EOF >> $HGRCPATH
1344 > [extensions]
1374 > [extensions]
1345 > # disable extension globally and explicitly
1375 > # disable extension globally and explicitly
1346 > reposetuptest = !
1376 > reposetuptest = !
1347 > EOF
1377 > EOF
1348 $ hg init parent
1378 $ hg init parent
1349 $ hg init parent/sub1
1379 $ hg init parent/sub1
1350 $ echo 1 > parent/sub1/1
1380 $ echo 1 > parent/sub1/1
1351 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1381 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1352 adding 1
1382 adding 1
1353 $ hg init parent/sub2
1383 $ hg init parent/sub2
1354 $ hg init parent/sub2/sub21
1384 $ hg init parent/sub2/sub21
1355 $ echo 21 > parent/sub2/sub21/21
1385 $ echo 21 > parent/sub2/sub21/21
1356 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1386 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1357 adding 21
1387 adding 21
1358 $ cat > parent/sub2/.hgsub <<EOF
1388 $ cat > parent/sub2/.hgsub <<EOF
1359 > sub21 = sub21
1389 > sub21 = sub21
1360 > EOF
1390 > EOF
1361 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1391 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1362 adding .hgsub
1392 adding .hgsub
1363 $ hg init parent/sub3
1393 $ hg init parent/sub3
1364 $ echo 3 > parent/sub3/3
1394 $ echo 3 > parent/sub3/3
1365 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1395 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1366 adding 3
1396 adding 3
1367 $ cat > parent/.hgsub <<EOF
1397 $ cat > parent/.hgsub <<EOF
1368 > sub1 = sub1
1398 > sub1 = sub1
1369 > sub2 = sub2
1399 > sub2 = sub2
1370 > sub3 = sub3
1400 > sub3 = sub3
1371 > EOF
1401 > EOF
1372 $ hg -R parent commit -Am '#0 at parent'
1402 $ hg -R parent commit -Am '#0 at parent'
1373 adding .hgsub
1403 adding .hgsub
1374 $ echo '[extensions]' >> parent/.hg/hgrc
1404 $ echo '[extensions]' >> parent/.hg/hgrc
1375 $ echo '# enable extension locally' >> parent/.hg/hgrc
1405 $ echo '# enable extension locally' >> parent/.hg/hgrc
1376 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1406 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1377 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1407 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1378 $ hg -R parent status -S -A
1408 $ hg -R parent status -S -A
1379 reposetup() for $TESTTMP/reposetup-test/parent (glob)
1409 reposetup() for $TESTTMP/reposetup-test/parent (glob)
1380 reposetup() for $TESTTMP/reposetup-test/parent/sub2 (glob)
1410 reposetup() for $TESTTMP/reposetup-test/parent/sub2 (glob)
1381 C .hgsub
1411 C .hgsub
1382 C .hgsubstate
1412 C .hgsubstate
1383 C sub1/1
1413 C sub1/1
1384 C sub2/.hgsub
1414 C sub2/.hgsub
1385 C sub2/.hgsubstate
1415 C sub2/.hgsubstate
1386 C sub2/sub21/21
1416 C sub2/sub21/21
1387 C sub3/3
1417 C sub3/3
1388
1418
1389 $ cd ..
1419 $ cd ..
1390
1420
1391 Test compatibility with extension commands that don't use @command (issue5137)
1421 Test compatibility with extension commands that don't use @command (issue5137)
1392
1422
1393 $ hg init deprecated
1423 $ hg init deprecated
1394 $ cd deprecated
1424 $ cd deprecated
1395
1425
1396 $ cat <<EOF > deprecatedcmd.py
1426 $ cat <<EOF > deprecatedcmd.py
1397 > def deprecatedcmd(repo, ui):
1427 > def deprecatedcmd(repo, ui):
1398 > pass
1428 > pass
1399 > cmdtable = {
1429 > cmdtable = {
1400 > 'deprecatedcmd': (deprecatedcmd, [], ''),
1430 > 'deprecatedcmd': (deprecatedcmd, [], ''),
1401 > }
1431 > }
1402 > EOF
1432 > EOF
1403 $ cat <<EOF > .hg/hgrc
1433 $ cat <<EOF > .hg/hgrc
1404 > [extensions]
1434 > [extensions]
1405 > deprecatedcmd = `pwd`/deprecatedcmd.py
1435 > deprecatedcmd = `pwd`/deprecatedcmd.py
1406 > mq = !
1436 > mq = !
1407 > hgext.mq = !
1437 > hgext.mq = !
1408 > hgext/mq = !
1438 > hgext/mq = !
1409 > [alias]
1439 > [alias]
1410 > deprecatedalias = deprecatedcmd
1440 > deprecatedalias = deprecatedcmd
1411 > EOF
1441 > EOF
1412
1442
1413 $ hg deprecatedcmd
1443 $ hg deprecatedcmd
1414 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedcmd'
1444 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedcmd'
1415 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1445 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1416
1446
1417 $ hg deprecatedalias
1447 $ hg deprecatedalias
1418 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedalias'
1448 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedalias'
1419 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1449 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1420
1450
1421 no warning unless command is executed:
1451 no warning unless command is executed:
1422
1452
1423 $ hg paths
1453 $ hg paths
1424
1454
1425 but mq iterates over command table:
1455 but mq iterates over command table:
1426
1456
1427 $ hg --config extensions.mq= paths
1457 $ hg --config extensions.mq= paths
1428 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedcmd'
1458 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedcmd'
1429 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1459 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1430
1460
1431 $ cd ..
1461 $ cd ..
1432
1462
1433 Test synopsis and docstring extending
1463 Test synopsis and docstring extending
1434
1464
1435 $ hg init exthelp
1465 $ hg init exthelp
1436 $ cat > exthelp.py <<EOF
1466 $ cat > exthelp.py <<EOF
1437 > from mercurial import commands, extensions
1467 > from mercurial import commands, extensions
1438 > def exbookmarks(orig, *args, **opts):
1468 > def exbookmarks(orig, *args, **opts):
1439 > return orig(*args, **opts)
1469 > return orig(*args, **opts)
1440 > def uisetup(ui):
1470 > def uisetup(ui):
1441 > synopsis = ' GREPME [--foo] [-x]'
1471 > synopsis = ' GREPME [--foo] [-x]'
1442 > docstring = '''
1472 > docstring = '''
1443 > GREPME make sure that this is in the help!
1473 > GREPME make sure that this is in the help!
1444 > '''
1474 > '''
1445 > extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
1475 > extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
1446 > synopsis, docstring)
1476 > synopsis, docstring)
1447 > EOF
1477 > EOF
1448 $ abspath=`pwd`/exthelp.py
1478 $ abspath=`pwd`/exthelp.py
1449 $ echo '[extensions]' >> $HGRCPATH
1479 $ echo '[extensions]' >> $HGRCPATH
1450 $ echo "exthelp = $abspath" >> $HGRCPATH
1480 $ echo "exthelp = $abspath" >> $HGRCPATH
1451 $ cd exthelp
1481 $ cd exthelp
1452 $ hg help bookmarks | grep GREPME
1482 $ hg help bookmarks | grep GREPME
1453 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1483 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1454 GREPME make sure that this is in the help!
1484 GREPME make sure that this is in the help!
1455
1485
General Comments 0
You need to be logged in to leave comments. Login now