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