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