##// END OF EJS Templates
help: show help for disabled extensions (issue5228)...
Pulkit Goyal -
r30306:5581b294 default
parent child Browse files
Show More
@@ -1,546 +1,546 b''
1 # extensions.py - extension handling for mercurial
1 # extensions.py - extension handling for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import imp
10 import imp
11 import os
11 import os
12
12
13 from .i18n import (
13 from .i18n import (
14 _,
14 _,
15 gettext,
15 gettext,
16 )
16 )
17
17
18 from . import (
18 from . import (
19 cmdutil,
19 cmdutil,
20 error,
20 error,
21 util,
21 util,
22 )
22 )
23
23
24 _extensions = {}
24 _extensions = {}
25 _disabledextensions = {}
25 _disabledextensions = {}
26 _aftercallbacks = {}
26 _aftercallbacks = {}
27 _order = []
27 _order = []
28 _builtin = set(['hbisect', 'bookmarks', 'parentrevspec', 'progress', 'interhg',
28 _builtin = set(['hbisect', 'bookmarks', 'parentrevspec', 'progress', 'interhg',
29 'inotify', 'hgcia'])
29 'inotify', 'hgcia'])
30
30
31 def extensions(ui=None):
31 def extensions(ui=None):
32 if ui:
32 if ui:
33 def enabled(name):
33 def enabled(name):
34 for format in ['%s', 'hgext.%s']:
34 for format in ['%s', 'hgext.%s']:
35 conf = ui.config('extensions', format % name)
35 conf = ui.config('extensions', format % name)
36 if conf is not None and not conf.startswith('!'):
36 if conf is not None and not conf.startswith('!'):
37 return True
37 return True
38 else:
38 else:
39 enabled = lambda name: True
39 enabled = lambda name: True
40 for name in _order:
40 for name in _order:
41 module = _extensions[name]
41 module = _extensions[name]
42 if module and enabled(name):
42 if module and enabled(name):
43 yield name, module
43 yield name, module
44
44
45 def find(name):
45 def find(name):
46 '''return module with given extension name'''
46 '''return module with given extension name'''
47 mod = None
47 mod = None
48 try:
48 try:
49 mod = _extensions[name]
49 mod = _extensions[name]
50 except KeyError:
50 except KeyError:
51 for k, v in _extensions.iteritems():
51 for k, v in _extensions.iteritems():
52 if k.endswith('.' + name) or k.endswith('/' + name):
52 if k.endswith('.' + name) or k.endswith('/' + name):
53 mod = v
53 mod = v
54 break
54 break
55 if not mod:
55 if not mod:
56 raise KeyError(name)
56 raise KeyError(name)
57 return mod
57 return mod
58
58
59 def loadpath(path, module_name):
59 def loadpath(path, module_name):
60 module_name = module_name.replace('.', '_')
60 module_name = module_name.replace('.', '_')
61 path = util.normpath(util.expandpath(path))
61 path = util.normpath(util.expandpath(path))
62 if os.path.isdir(path):
62 if os.path.isdir(path):
63 # module/__init__.py style
63 # module/__init__.py style
64 d, f = os.path.split(path)
64 d, f = os.path.split(path)
65 fd, fpath, desc = imp.find_module(f, [d])
65 fd, fpath, desc = imp.find_module(f, [d])
66 return imp.load_module(module_name, fd, fpath, desc)
66 return imp.load_module(module_name, fd, fpath, desc)
67 else:
67 else:
68 try:
68 try:
69 return imp.load_source(module_name, path)
69 return imp.load_source(module_name, path)
70 except IOError as exc:
70 except IOError as exc:
71 if not exc.filename:
71 if not exc.filename:
72 exc.filename = path # python does not fill this
72 exc.filename = path # python does not fill this
73 raise
73 raise
74
74
75 def _importh(name):
75 def _importh(name):
76 """import and return the <name> module"""
76 """import and return the <name> module"""
77 mod = __import__(name)
77 mod = __import__(name)
78 components = name.split('.')
78 components = name.split('.')
79 for comp in components[1:]:
79 for comp in components[1:]:
80 mod = getattr(mod, comp)
80 mod = getattr(mod, comp)
81 return mod
81 return mod
82
82
83 def _importext(name, path=None, reportfunc=None):
83 def _importext(name, path=None, reportfunc=None):
84 if path:
84 if path:
85 # the module will be loaded in sys.modules
85 # the module will be loaded in sys.modules
86 # choose an unique name so that it doesn't
86 # choose an unique name so that it doesn't
87 # conflicts with other modules
87 # conflicts with other modules
88 mod = loadpath(path, 'hgext.%s' % name)
88 mod = loadpath(path, 'hgext.%s' % name)
89 else:
89 else:
90 try:
90 try:
91 mod = _importh("hgext.%s" % name)
91 mod = _importh("hgext.%s" % name)
92 except ImportError as err:
92 except ImportError as err:
93 if reportfunc:
93 if reportfunc:
94 reportfunc(err, "hgext.%s" % name, "hgext3rd.%s" % name)
94 reportfunc(err, "hgext.%s" % name, "hgext3rd.%s" % name)
95 try:
95 try:
96 mod = _importh("hgext3rd.%s" % name)
96 mod = _importh("hgext3rd.%s" % name)
97 except ImportError as err:
97 except ImportError as err:
98 if reportfunc:
98 if reportfunc:
99 reportfunc(err, "hgext3rd.%s" % name, name)
99 reportfunc(err, "hgext3rd.%s" % name, name)
100 mod = _importh(name)
100 mod = _importh(name)
101 return mod
101 return mod
102
102
103 def _reportimporterror(ui, err, failed, next):
103 def _reportimporterror(ui, err, failed, next):
104 # note: this ui.debug happens before --debug is processed,
104 # note: this ui.debug happens before --debug is processed,
105 # Use --config ui.debug=1 to see them.
105 # Use --config ui.debug=1 to see them.
106 ui.debug('could not import %s (%s): trying %s\n'
106 ui.debug('could not import %s (%s): trying %s\n'
107 % (failed, err, next))
107 % (failed, err, next))
108 if ui.debugflag:
108 if ui.debugflag:
109 ui.traceback()
109 ui.traceback()
110
110
111 def load(ui, name, path):
111 def load(ui, name, path):
112 if name.startswith('hgext.') or name.startswith('hgext/'):
112 if name.startswith('hgext.') or name.startswith('hgext/'):
113 shortname = name[6:]
113 shortname = name[6:]
114 else:
114 else:
115 shortname = name
115 shortname = name
116 if shortname in _builtin:
116 if shortname in _builtin:
117 return None
117 return None
118 if shortname in _extensions:
118 if shortname in _extensions:
119 return _extensions[shortname]
119 return _extensions[shortname]
120 _extensions[shortname] = None
120 _extensions[shortname] = None
121 mod = _importext(name, path, bind(_reportimporterror, ui))
121 mod = _importext(name, path, bind(_reportimporterror, ui))
122
122
123 # Before we do anything with the extension, check against minimum stated
123 # Before we do anything with the extension, check against minimum stated
124 # compatibility. This gives extension authors a mechanism to have their
124 # compatibility. This gives extension authors a mechanism to have their
125 # extensions short circuit when loaded with a known incompatible version
125 # extensions short circuit when loaded with a known incompatible version
126 # of Mercurial.
126 # of Mercurial.
127 minver = getattr(mod, 'minimumhgversion', None)
127 minver = getattr(mod, 'minimumhgversion', None)
128 if minver and util.versiontuple(minver, 2) > util.versiontuple(n=2):
128 if minver and util.versiontuple(minver, 2) > util.versiontuple(n=2):
129 ui.warn(_('(third party extension %s requires version %s or newer '
129 ui.warn(_('(third party extension %s requires version %s or newer '
130 'of Mercurial; disabling)\n') % (shortname, minver))
130 'of Mercurial; disabling)\n') % (shortname, minver))
131 return
131 return
132
132
133 _extensions[shortname] = mod
133 _extensions[shortname] = mod
134 _order.append(shortname)
134 _order.append(shortname)
135 for fn in _aftercallbacks.get(shortname, []):
135 for fn in _aftercallbacks.get(shortname, []):
136 fn(loaded=True)
136 fn(loaded=True)
137 return mod
137 return mod
138
138
139 def _runuisetup(name, ui):
139 def _runuisetup(name, ui):
140 uisetup = getattr(_extensions[name], 'uisetup', None)
140 uisetup = getattr(_extensions[name], 'uisetup', None)
141 if uisetup:
141 if uisetup:
142 uisetup(ui)
142 uisetup(ui)
143
143
144 def _runextsetup(name, ui):
144 def _runextsetup(name, ui):
145 extsetup = getattr(_extensions[name], 'extsetup', None)
145 extsetup = getattr(_extensions[name], 'extsetup', None)
146 if extsetup:
146 if extsetup:
147 try:
147 try:
148 extsetup(ui)
148 extsetup(ui)
149 except TypeError:
149 except TypeError:
150 if extsetup.func_code.co_argcount != 0:
150 if extsetup.func_code.co_argcount != 0:
151 raise
151 raise
152 extsetup() # old extsetup with no ui argument
152 extsetup() # old extsetup with no ui argument
153
153
154 def loadall(ui):
154 def loadall(ui):
155 result = ui.configitems("extensions")
155 result = ui.configitems("extensions")
156 newindex = len(_order)
156 newindex = len(_order)
157 for (name, path) in result:
157 for (name, path) in result:
158 if path:
158 if path:
159 if path[0] == '!':
159 if path[0] == '!':
160 _disabledextensions[name] = path[1:]
160 _disabledextensions[name] = path[1:]
161 continue
161 continue
162 try:
162 try:
163 load(ui, name, path)
163 load(ui, name, path)
164 except KeyboardInterrupt:
164 except KeyboardInterrupt:
165 raise
165 raise
166 except Exception as inst:
166 except Exception as inst:
167 if path:
167 if path:
168 ui.warn(_("*** failed to import extension %s from %s: %s\n")
168 ui.warn(_("*** failed to import extension %s from %s: %s\n")
169 % (name, path, inst))
169 % (name, path, inst))
170 else:
170 else:
171 ui.warn(_("*** failed to import extension %s: %s\n")
171 ui.warn(_("*** failed to import extension %s: %s\n")
172 % (name, inst))
172 % (name, inst))
173 ui.traceback()
173 ui.traceback()
174
174
175 for name in _order[newindex:]:
175 for name in _order[newindex:]:
176 _runuisetup(name, ui)
176 _runuisetup(name, ui)
177
177
178 for name in _order[newindex:]:
178 for name in _order[newindex:]:
179 _runextsetup(name, ui)
179 _runextsetup(name, ui)
180
180
181 # Call aftercallbacks that were never met.
181 # Call aftercallbacks that were never met.
182 for shortname in _aftercallbacks:
182 for shortname in _aftercallbacks:
183 if shortname in _extensions:
183 if shortname in _extensions:
184 continue
184 continue
185
185
186 for fn in _aftercallbacks[shortname]:
186 for fn in _aftercallbacks[shortname]:
187 fn(loaded=False)
187 fn(loaded=False)
188
188
189 # loadall() is called multiple times and lingering _aftercallbacks
189 # loadall() is called multiple times and lingering _aftercallbacks
190 # entries could result in double execution. See issue4646.
190 # entries could result in double execution. See issue4646.
191 _aftercallbacks.clear()
191 _aftercallbacks.clear()
192
192
193 def afterloaded(extension, callback):
193 def afterloaded(extension, callback):
194 '''Run the specified function after a named extension is loaded.
194 '''Run the specified function after a named extension is loaded.
195
195
196 If the named extension is already loaded, the callback will be called
196 If the named extension is already loaded, the callback will be called
197 immediately.
197 immediately.
198
198
199 If the named extension never loads, the callback will be called after
199 If the named extension never loads, the callback will be called after
200 all extensions have been loaded.
200 all extensions have been loaded.
201
201
202 The callback receives the named argument ``loaded``, which is a boolean
202 The callback receives the named argument ``loaded``, which is a boolean
203 indicating whether the dependent extension actually loaded.
203 indicating whether the dependent extension actually loaded.
204 '''
204 '''
205
205
206 if extension in _extensions:
206 if extension in _extensions:
207 callback(loaded=True)
207 callback(loaded=True)
208 else:
208 else:
209 _aftercallbacks.setdefault(extension, []).append(callback)
209 _aftercallbacks.setdefault(extension, []).append(callback)
210
210
211 def bind(func, *args):
211 def bind(func, *args):
212 '''Partial function application
212 '''Partial function application
213
213
214 Returns a new function that is the partial application of args and kwargs
214 Returns a new function that is the partial application of args and kwargs
215 to func. For example,
215 to func. For example,
216
216
217 f(1, 2, bar=3) === bind(f, 1)(2, bar=3)'''
217 f(1, 2, bar=3) === bind(f, 1)(2, bar=3)'''
218 assert callable(func)
218 assert callable(func)
219 def closure(*a, **kw):
219 def closure(*a, **kw):
220 return func(*(args + a), **kw)
220 return func(*(args + a), **kw)
221 return closure
221 return closure
222
222
223 def _updatewrapper(wrap, origfn, unboundwrapper):
223 def _updatewrapper(wrap, origfn, unboundwrapper):
224 '''Copy and add some useful attributes to wrapper'''
224 '''Copy and add some useful attributes to wrapper'''
225 wrap.__module__ = getattr(origfn, '__module__')
225 wrap.__module__ = getattr(origfn, '__module__')
226 wrap.__doc__ = getattr(origfn, '__doc__')
226 wrap.__doc__ = getattr(origfn, '__doc__')
227 wrap.__dict__.update(getattr(origfn, '__dict__', {}))
227 wrap.__dict__.update(getattr(origfn, '__dict__', {}))
228 wrap._origfunc = origfn
228 wrap._origfunc = origfn
229 wrap._unboundwrapper = unboundwrapper
229 wrap._unboundwrapper = unboundwrapper
230
230
231 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
231 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
232 '''Wrap the command named `command' in table
232 '''Wrap the command named `command' in table
233
233
234 Replace command in the command table with wrapper. The wrapped command will
234 Replace command in the command table with wrapper. The wrapped command will
235 be inserted into the command table specified by the table argument.
235 be inserted into the command table specified by the table argument.
236
236
237 The wrapper will be called like
237 The wrapper will be called like
238
238
239 wrapper(orig, *args, **kwargs)
239 wrapper(orig, *args, **kwargs)
240
240
241 where orig is the original (wrapped) function, and *args, **kwargs
241 where orig is the original (wrapped) function, and *args, **kwargs
242 are the arguments passed to it.
242 are the arguments passed to it.
243
243
244 Optionally append to the command synopsis and docstring, used for help.
244 Optionally append to the command synopsis and docstring, used for help.
245 For example, if your extension wraps the ``bookmarks`` command to add the
245 For example, if your extension wraps the ``bookmarks`` command to add the
246 flags ``--remote`` and ``--all`` you might call this function like so:
246 flags ``--remote`` and ``--all`` you might call this function like so:
247
247
248 synopsis = ' [-a] [--remote]'
248 synopsis = ' [-a] [--remote]'
249 docstring = """
249 docstring = """
250
250
251 The ``remotenames`` extension adds the ``--remote`` and ``--all`` (``-a``)
251 The ``remotenames`` extension adds the ``--remote`` and ``--all`` (``-a``)
252 flags to the bookmarks command. Either flag will show the remote bookmarks
252 flags to the bookmarks command. Either flag will show the remote bookmarks
253 known to the repository; ``--remote`` will also suppress the output of the
253 known to the repository; ``--remote`` will also suppress the output of the
254 local bookmarks.
254 local bookmarks.
255 """
255 """
256
256
257 extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
257 extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
258 synopsis, docstring)
258 synopsis, docstring)
259 '''
259 '''
260 assert callable(wrapper)
260 assert callable(wrapper)
261 aliases, entry = cmdutil.findcmd(command, table)
261 aliases, entry = cmdutil.findcmd(command, table)
262 for alias, e in table.iteritems():
262 for alias, e in table.iteritems():
263 if e is entry:
263 if e is entry:
264 key = alias
264 key = alias
265 break
265 break
266
266
267 origfn = entry[0]
267 origfn = entry[0]
268 wrap = bind(util.checksignature(wrapper), util.checksignature(origfn))
268 wrap = bind(util.checksignature(wrapper), util.checksignature(origfn))
269 _updatewrapper(wrap, origfn, wrapper)
269 _updatewrapper(wrap, origfn, wrapper)
270 if docstring is not None:
270 if docstring is not None:
271 wrap.__doc__ += docstring
271 wrap.__doc__ += docstring
272
272
273 newentry = list(entry)
273 newentry = list(entry)
274 newentry[0] = wrap
274 newentry[0] = wrap
275 if synopsis is not None:
275 if synopsis is not None:
276 newentry[2] += synopsis
276 newentry[2] += synopsis
277 table[key] = tuple(newentry)
277 table[key] = tuple(newentry)
278 return entry
278 return entry
279
279
280 def wrapfunction(container, funcname, wrapper):
280 def wrapfunction(container, funcname, wrapper):
281 '''Wrap the function named funcname in container
281 '''Wrap the function named funcname in container
282
282
283 Replace the funcname member in the given container with the specified
283 Replace the funcname member in the given container with the specified
284 wrapper. The container is typically a module, class, or instance.
284 wrapper. The container is typically a module, class, or instance.
285
285
286 The wrapper will be called like
286 The wrapper will be called like
287
287
288 wrapper(orig, *args, **kwargs)
288 wrapper(orig, *args, **kwargs)
289
289
290 where orig is the original (wrapped) function, and *args, **kwargs
290 where orig is the original (wrapped) function, and *args, **kwargs
291 are the arguments passed to it.
291 are the arguments passed to it.
292
292
293 Wrapping methods of the repository object is not recommended since
293 Wrapping methods of the repository object is not recommended since
294 it conflicts with extensions that extend the repository by
294 it conflicts with extensions that extend the repository by
295 subclassing. All extensions that need to extend methods of
295 subclassing. All extensions that need to extend methods of
296 localrepository should use this subclassing trick: namely,
296 localrepository should use this subclassing trick: namely,
297 reposetup() should look like
297 reposetup() should look like
298
298
299 def reposetup(ui, repo):
299 def reposetup(ui, repo):
300 class myrepo(repo.__class__):
300 class myrepo(repo.__class__):
301 def whatever(self, *args, **kwargs):
301 def whatever(self, *args, **kwargs):
302 [...extension stuff...]
302 [...extension stuff...]
303 super(myrepo, self).whatever(*args, **kwargs)
303 super(myrepo, self).whatever(*args, **kwargs)
304 [...extension stuff...]
304 [...extension stuff...]
305
305
306 repo.__class__ = myrepo
306 repo.__class__ = myrepo
307
307
308 In general, combining wrapfunction() with subclassing does not
308 In general, combining wrapfunction() with subclassing does not
309 work. Since you cannot control what other extensions are loaded by
309 work. Since you cannot control what other extensions are loaded by
310 your end users, you should play nicely with others by using the
310 your end users, you should play nicely with others by using the
311 subclass trick.
311 subclass trick.
312 '''
312 '''
313 assert callable(wrapper)
313 assert callable(wrapper)
314
314
315 origfn = getattr(container, funcname)
315 origfn = getattr(container, funcname)
316 assert callable(origfn)
316 assert callable(origfn)
317 wrap = bind(wrapper, origfn)
317 wrap = bind(wrapper, origfn)
318 _updatewrapper(wrap, origfn, wrapper)
318 _updatewrapper(wrap, origfn, wrapper)
319 setattr(container, funcname, wrap)
319 setattr(container, funcname, wrap)
320 return origfn
320 return origfn
321
321
322 def unwrapfunction(container, funcname, wrapper=None):
322 def unwrapfunction(container, funcname, wrapper=None):
323 '''undo wrapfunction
323 '''undo wrapfunction
324
324
325 If wrappers is None, undo the last wrap. Otherwise removes the wrapper
325 If wrappers is None, undo the last wrap. Otherwise removes the wrapper
326 from the chain of wrappers.
326 from the chain of wrappers.
327
327
328 Return the removed wrapper.
328 Return the removed wrapper.
329 Raise IndexError if wrapper is None and nothing to unwrap; ValueError if
329 Raise IndexError if wrapper is None and nothing to unwrap; ValueError if
330 wrapper is not None but is not found in the wrapper chain.
330 wrapper is not None but is not found in the wrapper chain.
331 '''
331 '''
332 chain = getwrapperchain(container, funcname)
332 chain = getwrapperchain(container, funcname)
333 origfn = chain.pop()
333 origfn = chain.pop()
334 if wrapper is None:
334 if wrapper is None:
335 wrapper = chain[0]
335 wrapper = chain[0]
336 chain.remove(wrapper)
336 chain.remove(wrapper)
337 setattr(container, funcname, origfn)
337 setattr(container, funcname, origfn)
338 for w in reversed(chain):
338 for w in reversed(chain):
339 wrapfunction(container, funcname, w)
339 wrapfunction(container, funcname, w)
340 return wrapper
340 return wrapper
341
341
342 def getwrapperchain(container, funcname):
342 def getwrapperchain(container, funcname):
343 '''get a chain of wrappers of a function
343 '''get a chain of wrappers of a function
344
344
345 Return a list of functions: [newest wrapper, ..., oldest wrapper, origfunc]
345 Return a list of functions: [newest wrapper, ..., oldest wrapper, origfunc]
346
346
347 The wrapper functions are the ones passed to wrapfunction, whose first
347 The wrapper functions are the ones passed to wrapfunction, whose first
348 argument is origfunc.
348 argument is origfunc.
349 '''
349 '''
350 result = []
350 result = []
351 fn = getattr(container, funcname)
351 fn = getattr(container, funcname)
352 while fn:
352 while fn:
353 assert callable(fn)
353 assert callable(fn)
354 result.append(getattr(fn, '_unboundwrapper', fn))
354 result.append(getattr(fn, '_unboundwrapper', fn))
355 fn = getattr(fn, '_origfunc', None)
355 fn = getattr(fn, '_origfunc', None)
356 return result
356 return result
357
357
358 def _disabledpaths(strip_init=False):
358 def _disabledpaths(strip_init=False):
359 '''find paths of disabled extensions. returns a dict of {name: path}
359 '''find paths of disabled extensions. returns a dict of {name: path}
360 removes /__init__.py from packages if strip_init is True'''
360 removes /__init__.py from packages if strip_init is True'''
361 import hgext
361 import hgext
362 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
362 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
363 try: # might not be a filesystem path
363 try: # might not be a filesystem path
364 files = os.listdir(extpath)
364 files = os.listdir(extpath)
365 except OSError:
365 except OSError:
366 return {}
366 return {}
367
367
368 exts = {}
368 exts = {}
369 for e in files:
369 for e in files:
370 if e.endswith('.py'):
370 if e.endswith('.py'):
371 name = e.rsplit('.', 1)[0]
371 name = e.rsplit('.', 1)[0]
372 path = os.path.join(extpath, e)
372 path = os.path.join(extpath, e)
373 else:
373 else:
374 name = e
374 name = e
375 path = os.path.join(extpath, e, '__init__.py')
375 path = os.path.join(extpath, e, '__init__.py')
376 if not os.path.exists(path):
376 if not os.path.exists(path):
377 continue
377 continue
378 if strip_init:
378 if strip_init:
379 path = os.path.dirname(path)
379 path = os.path.dirname(path)
380 if name in exts or name in _order or name == '__init__':
380 if name in exts or name in _order or name == '__init__':
381 continue
381 continue
382 exts[name] = path
382 exts[name] = path
383 exts.update(_disabledextensions)
383 exts.update(_disabledextensions)
384 return exts
384 return exts
385
385
386 def _moduledoc(file):
386 def _moduledoc(file):
387 '''return the top-level python documentation for the given file
387 '''return the top-level python documentation for the given file
388
388
389 Loosely inspired by pydoc.source_synopsis(), but rewritten to
389 Loosely inspired by pydoc.source_synopsis(), but rewritten to
390 handle triple quotes and to return the whole text instead of just
390 handle triple quotes and to return the whole text instead of just
391 the synopsis'''
391 the synopsis'''
392 result = []
392 result = []
393
393
394 line = file.readline()
394 line = file.readline()
395 while line[:1] == '#' or not line.strip():
395 while line[:1] == '#' or not line.strip():
396 line = file.readline()
396 line = file.readline()
397 if not line:
397 if not line:
398 break
398 break
399
399
400 start = line[:3]
400 start = line[:3]
401 if start == '"""' or start == "'''":
401 if start == '"""' or start == "'''":
402 line = line[3:]
402 line = line[3:]
403 while line:
403 while line:
404 if line.rstrip().endswith(start):
404 if line.rstrip().endswith(start):
405 line = line.split(start)[0]
405 line = line.split(start)[0]
406 if line:
406 if line:
407 result.append(line)
407 result.append(line)
408 break
408 break
409 elif not line:
409 elif not line:
410 return None # unmatched delimiter
410 return None # unmatched delimiter
411 result.append(line)
411 result.append(line)
412 line = file.readline()
412 line = file.readline()
413 else:
413 else:
414 return None
414 return None
415
415
416 return ''.join(result)
416 return ''.join(result)
417
417
418 def _disabledhelp(path):
418 def _disabledhelp(path):
419 '''retrieve help synopsis of a disabled extension (without importing)'''
419 '''retrieve help synopsis of a disabled extension (without importing)'''
420 try:
420 try:
421 file = open(path)
421 file = open(path)
422 except IOError:
422 except IOError:
423 return
423 return
424 else:
424 else:
425 doc = _moduledoc(file)
425 doc = _moduledoc(file)
426 file.close()
426 file.close()
427
427
428 if doc: # extracting localized synopsis
428 if doc: # extracting localized synopsis
429 return gettext(doc).splitlines()[0]
429 return gettext(doc)
430 else:
430 else:
431 return _('(no help text available)')
431 return _('(no help text available)')
432
432
433 def disabled():
433 def disabled():
434 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
434 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
435 try:
435 try:
436 from hgext import __index__
436 from hgext import __index__
437 return dict((name, gettext(desc))
437 return dict((name, gettext(desc))
438 for name, desc in __index__.docs.iteritems()
438 for name, desc in __index__.docs.iteritems()
439 if name not in _order)
439 if name not in _order)
440 except (ImportError, AttributeError):
440 except (ImportError, AttributeError):
441 pass
441 pass
442
442
443 paths = _disabledpaths()
443 paths = _disabledpaths()
444 if not paths:
444 if not paths:
445 return {}
445 return {}
446
446
447 exts = {}
447 exts = {}
448 for name, path in paths.iteritems():
448 for name, path in paths.iteritems():
449 doc = _disabledhelp(path)
449 doc = _disabledhelp(path)
450 if doc:
450 if doc:
451 exts[name] = doc
451 exts[name] = doc.splitlines()[0]
452
452
453 return exts
453 return exts
454
454
455 def disabledext(name):
455 def disabledext(name):
456 '''find a specific disabled extension from hgext. returns desc'''
456 '''find a specific disabled extension from hgext. returns desc'''
457 try:
457 try:
458 from hgext import __index__
458 from hgext import __index__
459 if name in _order: # enabled
459 if name in _order: # enabled
460 return
460 return
461 else:
461 else:
462 return gettext(__index__.docs.get(name))
462 return gettext(__index__.docs.get(name))
463 except (ImportError, AttributeError):
463 except (ImportError, AttributeError):
464 pass
464 pass
465
465
466 paths = _disabledpaths()
466 paths = _disabledpaths()
467 if name in paths:
467 if name in paths:
468 return _disabledhelp(paths[name])
468 return _disabledhelp(paths[name])
469
469
470 def disabledcmd(ui, cmd, strict=False):
470 def disabledcmd(ui, cmd, strict=False):
471 '''import disabled extensions until cmd is found.
471 '''import disabled extensions until cmd is found.
472 returns (cmdname, extname, module)'''
472 returns (cmdname, extname, module)'''
473
473
474 paths = _disabledpaths(strip_init=True)
474 paths = _disabledpaths(strip_init=True)
475 if not paths:
475 if not paths:
476 raise error.UnknownCommand(cmd)
476 raise error.UnknownCommand(cmd)
477
477
478 def findcmd(cmd, name, path):
478 def findcmd(cmd, name, path):
479 try:
479 try:
480 mod = loadpath(path, 'hgext.%s' % name)
480 mod = loadpath(path, 'hgext.%s' % name)
481 except Exception:
481 except Exception:
482 return
482 return
483 try:
483 try:
484 aliases, entry = cmdutil.findcmd(cmd,
484 aliases, entry = cmdutil.findcmd(cmd,
485 getattr(mod, 'cmdtable', {}), strict)
485 getattr(mod, 'cmdtable', {}), strict)
486 except (error.AmbiguousCommand, error.UnknownCommand):
486 except (error.AmbiguousCommand, error.UnknownCommand):
487 return
487 return
488 except Exception:
488 except Exception:
489 ui.warn(_('warning: error finding commands in %s\n') % path)
489 ui.warn(_('warning: error finding commands in %s\n') % path)
490 ui.traceback()
490 ui.traceback()
491 return
491 return
492 for c in aliases:
492 for c in aliases:
493 if c.startswith(cmd):
493 if c.startswith(cmd):
494 cmd = c
494 cmd = c
495 break
495 break
496 else:
496 else:
497 cmd = aliases[0]
497 cmd = aliases[0]
498 return (cmd, name, mod)
498 return (cmd, name, mod)
499
499
500 ext = None
500 ext = None
501 # first, search for an extension with the same name as the command
501 # first, search for an extension with the same name as the command
502 path = paths.pop(cmd, None)
502 path = paths.pop(cmd, None)
503 if path:
503 if path:
504 ext = findcmd(cmd, cmd, path)
504 ext = findcmd(cmd, cmd, path)
505 if not ext:
505 if not ext:
506 # otherwise, interrogate each extension until there's a match
506 # otherwise, interrogate each extension until there's a match
507 for name, path in paths.iteritems():
507 for name, path in paths.iteritems():
508 ext = findcmd(cmd, name, path)
508 ext = findcmd(cmd, name, path)
509 if ext:
509 if ext:
510 break
510 break
511 if ext and 'DEPRECATED' not in ext.__doc__:
511 if ext and 'DEPRECATED' not in ext.__doc__:
512 return ext
512 return ext
513
513
514 raise error.UnknownCommand(cmd)
514 raise error.UnknownCommand(cmd)
515
515
516 def enabled(shortname=True):
516 def enabled(shortname=True):
517 '''return a dict of {name: desc} of extensions'''
517 '''return a dict of {name: desc} of extensions'''
518 exts = {}
518 exts = {}
519 for ename, ext in extensions():
519 for ename, ext in extensions():
520 doc = (gettext(ext.__doc__) or _('(no help text available)'))
520 doc = (gettext(ext.__doc__) or _('(no help text available)'))
521 if shortname:
521 if shortname:
522 ename = ename.split('.')[-1]
522 ename = ename.split('.')[-1]
523 exts[ename] = doc.splitlines()[0].strip()
523 exts[ename] = doc.splitlines()[0].strip()
524
524
525 return exts
525 return exts
526
526
527 def notloaded():
527 def notloaded():
528 '''return short names of extensions that failed to load'''
528 '''return short names of extensions that failed to load'''
529 return [name for name, mod in _extensions.iteritems() if mod is None]
529 return [name for name, mod in _extensions.iteritems() if mod is None]
530
530
531 def moduleversion(module):
531 def moduleversion(module):
532 '''return version information from given module as a string'''
532 '''return version information from given module as a string'''
533 if (util.safehasattr(module, 'getversion')
533 if (util.safehasattr(module, 'getversion')
534 and callable(module.getversion)):
534 and callable(module.getversion)):
535 version = module.getversion()
535 version = module.getversion()
536 elif util.safehasattr(module, '__version__'):
536 elif util.safehasattr(module, '__version__'):
537 version = module.__version__
537 version = module.__version__
538 else:
538 else:
539 version = ''
539 version = ''
540 if isinstance(version, (list, tuple)):
540 if isinstance(version, (list, tuple)):
541 version = '.'.join(str(o) for o in version)
541 version = '.'.join(str(o) for o in version)
542 return version
542 return version
543
543
544 def ismoduleinternal(module):
544 def ismoduleinternal(module):
545 exttestedwith = getattr(module, 'testedwith', None)
545 exttestedwith = getattr(module, 'testedwith', None)
546 return exttestedwith == "ships-with-hg-core"
546 return exttestedwith == "ships-with-hg-core"
@@ -1,1522 +1,1577 b''
1 Test basic extension support
1 Test basic extension support
2
2
3 $ cat > foobar.py <<EOF
3 $ cat > foobar.py <<EOF
4 > import os
4 > import os
5 > from mercurial import cmdutil, commands
5 > from mercurial import cmdutil, commands
6 > cmdtable = {}
6 > cmdtable = {}
7 > command = cmdutil.command(cmdtable)
7 > command = cmdutil.command(cmdtable)
8 > def uisetup(ui):
8 > def uisetup(ui):
9 > ui.write("uisetup called\\n")
9 > ui.write("uisetup called\\n")
10 > ui.flush()
10 > ui.flush()
11 > def reposetup(ui, repo):
11 > def reposetup(ui, repo):
12 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
12 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
13 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
13 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
14 > ui.flush()
14 > ui.flush()
15 > @command('foo', [], 'hg foo')
15 > @command('foo', [], 'hg foo')
16 > def foo(ui, *args, **kwargs):
16 > def foo(ui, *args, **kwargs):
17 > ui.write("Foo\\n")
17 > ui.write("Foo\\n")
18 > @command('bar', [], 'hg bar', norepo=True)
18 > @command('bar', [], 'hg bar', norepo=True)
19 > def bar(ui, *args, **kwargs):
19 > def bar(ui, *args, **kwargs):
20 > ui.write("Bar\\n")
20 > ui.write("Bar\\n")
21 > EOF
21 > EOF
22 $ abspath=`pwd`/foobar.py
22 $ abspath=`pwd`/foobar.py
23
23
24 $ mkdir barfoo
24 $ mkdir barfoo
25 $ cp foobar.py barfoo/__init__.py
25 $ cp foobar.py barfoo/__init__.py
26 $ barfoopath=`pwd`/barfoo
26 $ barfoopath=`pwd`/barfoo
27
27
28 $ hg init a
28 $ hg init a
29 $ cd a
29 $ cd a
30 $ echo foo > file
30 $ echo foo > file
31 $ hg add file
31 $ hg add file
32 $ hg commit -m 'add file'
32 $ hg commit -m 'add file'
33
33
34 $ echo '[extensions]' >> $HGRCPATH
34 $ echo '[extensions]' >> $HGRCPATH
35 $ echo "foobar = $abspath" >> $HGRCPATH
35 $ echo "foobar = $abspath" >> $HGRCPATH
36 $ hg foo
36 $ hg foo
37 uisetup called
37 uisetup called
38 reposetup called for a
38 reposetup called for a
39 ui == repo.ui
39 ui == repo.ui
40 Foo
40 Foo
41
41
42 $ cd ..
42 $ cd ..
43 $ hg clone a b
43 $ hg clone a b
44 uisetup called
44 uisetup called
45 reposetup called for a
45 reposetup called for a
46 ui == repo.ui
46 ui == repo.ui
47 reposetup called for b
47 reposetup called for b
48 ui == repo.ui
48 ui == repo.ui
49 updating to branch default
49 updating to branch default
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
51
51
52 $ hg bar
52 $ hg bar
53 uisetup called
53 uisetup called
54 Bar
54 Bar
55 $ echo 'foobar = !' >> $HGRCPATH
55 $ echo 'foobar = !' >> $HGRCPATH
56
56
57 module/__init__.py-style
57 module/__init__.py-style
58
58
59 $ echo "barfoo = $barfoopath" >> $HGRCPATH
59 $ echo "barfoo = $barfoopath" >> $HGRCPATH
60 $ cd a
60 $ cd a
61 $ hg foo
61 $ hg foo
62 uisetup called
62 uisetup called
63 reposetup called for a
63 reposetup called for a
64 ui == repo.ui
64 ui == repo.ui
65 Foo
65 Foo
66 $ echo 'barfoo = !' >> $HGRCPATH
66 $ echo 'barfoo = !' >> $HGRCPATH
67
67
68 Check that extensions are loaded in phases:
68 Check that extensions are loaded in phases:
69
69
70 $ cat > foo.py <<EOF
70 $ cat > foo.py <<EOF
71 > import os
71 > import os
72 > name = os.path.basename(__file__).rsplit('.', 1)[0]
72 > name = os.path.basename(__file__).rsplit('.', 1)[0]
73 > print "1) %s imported" % name
73 > print "1) %s imported" % name
74 > def uisetup(ui):
74 > def uisetup(ui):
75 > print "2) %s uisetup" % name
75 > print "2) %s uisetup" % name
76 > def extsetup():
76 > def extsetup():
77 > print "3) %s extsetup" % name
77 > print "3) %s extsetup" % name
78 > def reposetup(ui, repo):
78 > def reposetup(ui, repo):
79 > print "4) %s reposetup" % name
79 > print "4) %s reposetup" % name
80 > EOF
80 > EOF
81
81
82 $ cp foo.py bar.py
82 $ cp foo.py bar.py
83 $ echo 'foo = foo.py' >> $HGRCPATH
83 $ echo 'foo = foo.py' >> $HGRCPATH
84 $ echo 'bar = bar.py' >> $HGRCPATH
84 $ echo 'bar = bar.py' >> $HGRCPATH
85
85
86 Command with no output, we just want to see the extensions loaded:
86 Command with no output, we just want to see the extensions loaded:
87
87
88 $ hg paths
88 $ hg paths
89 1) foo imported
89 1) foo imported
90 1) bar imported
90 1) bar imported
91 2) foo uisetup
91 2) foo uisetup
92 2) bar uisetup
92 2) bar uisetup
93 3) foo extsetup
93 3) foo extsetup
94 3) bar extsetup
94 3) bar extsetup
95 4) foo reposetup
95 4) foo reposetup
96 4) bar reposetup
96 4) bar reposetup
97
97
98 Check hgweb's load order:
98 Check hgweb's load order:
99
99
100 $ cat > hgweb.cgi <<EOF
100 $ cat > hgweb.cgi <<EOF
101 > #!/usr/bin/env python
101 > #!/usr/bin/env python
102 > from mercurial import demandimport; demandimport.enable()
102 > from mercurial import demandimport; demandimport.enable()
103 > from mercurial.hgweb import hgweb
103 > from mercurial.hgweb import hgweb
104 > from mercurial.hgweb import wsgicgi
104 > from mercurial.hgweb import wsgicgi
105 > application = hgweb('.', 'test repo')
105 > application = hgweb('.', 'test repo')
106 > wsgicgi.launch(application)
106 > wsgicgi.launch(application)
107 > EOF
107 > EOF
108
108
109 $ REQUEST_METHOD='GET' PATH_INFO='/' SCRIPT_NAME='' QUERY_STRING='' \
109 $ REQUEST_METHOD='GET' PATH_INFO='/' SCRIPT_NAME='' QUERY_STRING='' \
110 > SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
110 > SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
111 > | grep '^[0-9]) ' # ignores HTML output
111 > | grep '^[0-9]) ' # ignores HTML output
112 1) foo imported
112 1) foo imported
113 1) bar imported
113 1) bar imported
114 2) foo uisetup
114 2) foo uisetup
115 2) bar uisetup
115 2) bar uisetup
116 3) foo extsetup
116 3) foo extsetup
117 3) bar extsetup
117 3) bar extsetup
118 4) foo reposetup
118 4) foo reposetup
119 4) bar reposetup
119 4) bar reposetup
120
120
121 $ echo 'foo = !' >> $HGRCPATH
121 $ echo 'foo = !' >> $HGRCPATH
122 $ echo 'bar = !' >> $HGRCPATH
122 $ echo 'bar = !' >> $HGRCPATH
123
123
124 Check "from __future__ import absolute_import" support for external libraries
124 Check "from __future__ import absolute_import" support for external libraries
125
125
126 #if windows
126 #if windows
127 $ PATHSEP=";"
127 $ PATHSEP=";"
128 #else
128 #else
129 $ PATHSEP=":"
129 $ PATHSEP=":"
130 #endif
130 #endif
131 $ export PATHSEP
131 $ export PATHSEP
132
132
133 $ mkdir $TESTTMP/libroot
133 $ mkdir $TESTTMP/libroot
134 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
134 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
135 $ mkdir $TESTTMP/libroot/mod
135 $ mkdir $TESTTMP/libroot/mod
136 $ touch $TESTTMP/libroot/mod/__init__.py
136 $ touch $TESTTMP/libroot/mod/__init__.py
137 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
137 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
138
138
139 #if absimport
139 #if absimport
140 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF
140 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF
141 > from __future__ import absolute_import
141 > from __future__ import absolute_import
142 > import ambig # should load "libroot/ambig.py"
142 > import ambig # should load "libroot/ambig.py"
143 > s = ambig.s
143 > s = ambig.s
144 > EOF
144 > EOF
145 $ cat > loadabs.py <<EOF
145 $ cat > loadabs.py <<EOF
146 > import mod.ambigabs as ambigabs
146 > import mod.ambigabs as ambigabs
147 > def extsetup():
147 > def extsetup():
148 > print 'ambigabs.s=%s' % ambigabs.s
148 > print 'ambigabs.s=%s' % ambigabs.s
149 > EOF
149 > EOF
150 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
150 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
151 ambigabs.s=libroot/ambig.py
151 ambigabs.s=libroot/ambig.py
152 $TESTTMP/a (glob)
152 $TESTTMP/a (glob)
153 #endif
153 #endif
154
154
155 #if no-py3k
155 #if no-py3k
156 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF
156 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF
157 > import ambig # should load "libroot/mod/ambig.py"
157 > import ambig # should load "libroot/mod/ambig.py"
158 > s = ambig.s
158 > s = ambig.s
159 > EOF
159 > EOF
160 $ cat > loadrel.py <<EOF
160 $ cat > loadrel.py <<EOF
161 > import mod.ambigrel as ambigrel
161 > import mod.ambigrel as ambigrel
162 > def extsetup():
162 > def extsetup():
163 > print 'ambigrel.s=%s' % ambigrel.s
163 > print 'ambigrel.s=%s' % ambigrel.s
164 > EOF
164 > EOF
165 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
165 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
166 ambigrel.s=libroot/mod/ambig.py
166 ambigrel.s=libroot/mod/ambig.py
167 $TESTTMP/a (glob)
167 $TESTTMP/a (glob)
168 #endif
168 #endif
169
169
170 Check absolute/relative import of extension specific modules
170 Check absolute/relative import of extension specific modules
171
171
172 $ mkdir $TESTTMP/extroot
172 $ mkdir $TESTTMP/extroot
173 $ cat > $TESTTMP/extroot/bar.py <<EOF
173 $ cat > $TESTTMP/extroot/bar.py <<EOF
174 > s = 'this is extroot.bar'
174 > s = 'this is extroot.bar'
175 > EOF
175 > EOF
176 $ mkdir $TESTTMP/extroot/sub1
176 $ mkdir $TESTTMP/extroot/sub1
177 $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF
177 $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF
178 > s = 'this is extroot.sub1.__init__'
178 > s = 'this is extroot.sub1.__init__'
179 > EOF
179 > EOF
180 $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF
180 $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF
181 > s = 'this is extroot.sub1.baz'
181 > s = 'this is extroot.sub1.baz'
182 > EOF
182 > EOF
183 $ cat > $TESTTMP/extroot/__init__.py <<EOF
183 $ cat > $TESTTMP/extroot/__init__.py <<EOF
184 > s = 'this is extroot.__init__'
184 > s = 'this is extroot.__init__'
185 > import foo
185 > import foo
186 > def extsetup(ui):
186 > def extsetup(ui):
187 > ui.write('(extroot) ', foo.func(), '\n')
187 > ui.write('(extroot) ', foo.func(), '\n')
188 > ui.flush()
188 > ui.flush()
189 > EOF
189 > EOF
190
190
191 $ cat > $TESTTMP/extroot/foo.py <<EOF
191 $ cat > $TESTTMP/extroot/foo.py <<EOF
192 > # test absolute import
192 > # test absolute import
193 > buf = []
193 > buf = []
194 > def func():
194 > def func():
195 > # "not locals" case
195 > # "not locals" case
196 > import extroot.bar
196 > import extroot.bar
197 > buf.append('import extroot.bar in func(): %s' % extroot.bar.s)
197 > buf.append('import extroot.bar in func(): %s' % extroot.bar.s)
198 > return '\n(extroot) '.join(buf)
198 > return '\n(extroot) '.join(buf)
199 > # "fromlist == ('*',)" case
199 > # "fromlist == ('*',)" case
200 > from extroot.bar import *
200 > from extroot.bar import *
201 > buf.append('from extroot.bar import *: %s' % s)
201 > buf.append('from extroot.bar import *: %s' % s)
202 > # "not fromlist" and "if '.' in name" case
202 > # "not fromlist" and "if '.' in name" case
203 > import extroot.sub1.baz
203 > import extroot.sub1.baz
204 > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
204 > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
205 > # "not fromlist" and NOT "if '.' in name" case
205 > # "not fromlist" and NOT "if '.' in name" case
206 > import extroot
206 > import extroot
207 > buf.append('import extroot: %s' % extroot.s)
207 > buf.append('import extroot: %s' % extroot.s)
208 > # NOT "not fromlist" and NOT "level != -1" case
208 > # NOT "not fromlist" and NOT "level != -1" case
209 > from extroot.bar import s
209 > from extroot.bar import s
210 > buf.append('from extroot.bar import s: %s' % s)
210 > buf.append('from extroot.bar import s: %s' % s)
211 > EOF
211 > EOF
212 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
212 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
213 (extroot) from extroot.bar import *: this is extroot.bar
213 (extroot) from extroot.bar import *: this is extroot.bar
214 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
214 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
215 (extroot) import extroot: this is extroot.__init__
215 (extroot) import extroot: this is extroot.__init__
216 (extroot) from extroot.bar import s: this is extroot.bar
216 (extroot) from extroot.bar import s: this is extroot.bar
217 (extroot) import extroot.bar in func(): this is extroot.bar
217 (extroot) import extroot.bar in func(): this is extroot.bar
218 $TESTTMP/a (glob)
218 $TESTTMP/a (glob)
219
219
220 #if no-py3k
220 #if no-py3k
221 $ rm "$TESTTMP"/extroot/foo.*
221 $ rm "$TESTTMP"/extroot/foo.*
222 $ cat > $TESTTMP/extroot/foo.py <<EOF
222 $ cat > $TESTTMP/extroot/foo.py <<EOF
223 > # test relative import
223 > # test relative import
224 > buf = []
224 > buf = []
225 > def func():
225 > def func():
226 > # "not locals" case
226 > # "not locals" case
227 > import bar
227 > import bar
228 > buf.append('import bar in func(): %s' % bar.s)
228 > buf.append('import bar in func(): %s' % bar.s)
229 > return '\n(extroot) '.join(buf)
229 > return '\n(extroot) '.join(buf)
230 > # "fromlist == ('*',)" case
230 > # "fromlist == ('*',)" case
231 > from bar import *
231 > from bar import *
232 > buf.append('from bar import *: %s' % s)
232 > buf.append('from bar import *: %s' % s)
233 > # "not fromlist" and "if '.' in name" case
233 > # "not fromlist" and "if '.' in name" case
234 > import sub1.baz
234 > import sub1.baz
235 > buf.append('import sub1.baz: %s' % sub1.baz.s)
235 > buf.append('import sub1.baz: %s' % sub1.baz.s)
236 > # "not fromlist" and NOT "if '.' in name" case
236 > # "not fromlist" and NOT "if '.' in name" case
237 > import sub1
237 > import sub1
238 > buf.append('import sub1: %s' % sub1.s)
238 > buf.append('import sub1: %s' % sub1.s)
239 > # NOT "not fromlist" and NOT "level != -1" case
239 > # NOT "not fromlist" and NOT "level != -1" case
240 > from bar import s
240 > from bar import s
241 > buf.append('from bar import s: %s' % s)
241 > buf.append('from bar import s: %s' % s)
242 > EOF
242 > EOF
243 $ hg --config extensions.extroot=$TESTTMP/extroot root
243 $ hg --config extensions.extroot=$TESTTMP/extroot root
244 (extroot) from bar import *: this is extroot.bar
244 (extroot) from bar import *: this is extroot.bar
245 (extroot) import sub1.baz: this is extroot.sub1.baz
245 (extroot) import sub1.baz: this is extroot.sub1.baz
246 (extroot) import sub1: this is extroot.sub1.__init__
246 (extroot) import sub1: this is extroot.sub1.__init__
247 (extroot) from bar import s: this is extroot.bar
247 (extroot) from bar import s: this is extroot.bar
248 (extroot) import bar in func(): this is extroot.bar
248 (extroot) import bar in func(): this is extroot.bar
249 $TESTTMP/a (glob)
249 $TESTTMP/a (glob)
250 #endif
250 #endif
251
251
252 #if demandimport absimport
252 #if demandimport absimport
253
253
254 Examine whether module loading is delayed until actual refering, even
254 Examine whether module loading is delayed until actual refering, even
255 though module is imported with "absolute_import" feature.
255 though module is imported with "absolute_import" feature.
256
256
257 Files below in each packages are used for descirbed purpose:
257 Files below in each packages are used for descirbed purpose:
258
258
259 - "called": examine whether "from MODULE import ATTR" works correctly
259 - "called": examine whether "from MODULE import ATTR" works correctly
260 - "unused": examine whether loading is delayed correctly
260 - "unused": examine whether loading is delayed correctly
261 - "used": examine whether "from PACKAGE import MODULE" works correctly
261 - "used": examine whether "from PACKAGE import MODULE" works correctly
262
262
263 Package hierarchy is needed to examine whether demand importing works
263 Package hierarchy is needed to examine whether demand importing works
264 as expected for "from SUB.PACK.AGE import MODULE".
264 as expected for "from SUB.PACK.AGE import MODULE".
265
265
266 Setup "external library" to be imported with "absolute_import"
266 Setup "external library" to be imported with "absolute_import"
267 feature.
267 feature.
268
268
269 $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2
269 $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2
270 $ touch $TESTTMP/extlibroot/__init__.py
270 $ touch $TESTTMP/extlibroot/__init__.py
271 $ touch $TESTTMP/extlibroot/lsub1/__init__.py
271 $ touch $TESTTMP/extlibroot/lsub1/__init__.py
272 $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py
272 $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py
273
273
274 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<EOF
274 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<EOF
275 > def func():
275 > def func():
276 > return "this is extlibroot.lsub1.lsub2.called.func()"
276 > return "this is extlibroot.lsub1.lsub2.called.func()"
277 > EOF
277 > EOF
278 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<EOF
278 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<EOF
279 > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally")
279 > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally")
280 > EOF
280 > EOF
281 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<EOF
281 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<EOF
282 > detail = "this is extlibroot.lsub1.lsub2.used"
282 > detail = "this is extlibroot.lsub1.lsub2.used"
283 > EOF
283 > EOF
284
284
285 Setup sub-package of "external library", which causes instantiation of
285 Setup sub-package of "external library", which causes instantiation of
286 demandmod in "recurse down the module chain" code path. Relative
286 demandmod in "recurse down the module chain" code path. Relative
287 importing with "absolute_import" feature isn't tested, because "level
287 importing with "absolute_import" feature isn't tested, because "level
288 >=1 " doesn't cause instantiation of demandmod.
288 >=1 " doesn't cause instantiation of demandmod.
289
289
290 $ mkdir -p $TESTTMP/extlibroot/recursedown/abs
290 $ mkdir -p $TESTTMP/extlibroot/recursedown/abs
291 $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<EOF
291 $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<EOF
292 > detail = "this is extlibroot.recursedown.abs.used"
292 > detail = "this is extlibroot.recursedown.abs.used"
293 > EOF
293 > EOF
294 $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<EOF
294 $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<EOF
295 > from __future__ import absolute_import
295 > from __future__ import absolute_import
296 > from extlibroot.recursedown.abs.used import detail
296 > from extlibroot.recursedown.abs.used import detail
297 > EOF
297 > EOF
298
298
299 $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy
299 $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy
300 $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<EOF
300 $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<EOF
301 > detail = "this is extlibroot.recursedown.legacy.used"
301 > detail = "this is extlibroot.recursedown.legacy.used"
302 > EOF
302 > EOF
303 $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<EOF
303 $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<EOF
304 > # legacy style (level == -1) import
304 > # legacy style (level == -1) import
305 > from extlibroot.recursedown.legacy.used import detail
305 > from extlibroot.recursedown.legacy.used import detail
306 > EOF
306 > EOF
307
307
308 $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<EOF
308 $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<EOF
309 > from __future__ import absolute_import
309 > from __future__ import absolute_import
310 > from extlibroot.recursedown.abs import detail as absdetail
310 > from extlibroot.recursedown.abs import detail as absdetail
311 > from .legacy import detail as legacydetail
311 > from .legacy import detail as legacydetail
312 > EOF
312 > EOF
313
313
314 Setup extension local modules to be imported with "absolute_import"
314 Setup extension local modules to be imported with "absolute_import"
315 feature.
315 feature.
316
316
317 $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2
317 $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2
318 $ touch $TESTTMP/absextroot/xsub1/__init__.py
318 $ touch $TESTTMP/absextroot/xsub1/__init__.py
319 $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py
319 $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py
320
320
321 $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<EOF
321 $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<EOF
322 > def func():
322 > def func():
323 > return "this is absextroot.xsub1.xsub2.called.func()"
323 > return "this is absextroot.xsub1.xsub2.called.func()"
324 > EOF
324 > EOF
325 $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<EOF
325 $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<EOF
326 > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally")
326 > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally")
327 > EOF
327 > EOF
328 $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<EOF
328 $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<EOF
329 > detail = "this is absextroot.xsub1.xsub2.used"
329 > detail = "this is absextroot.xsub1.xsub2.used"
330 > EOF
330 > EOF
331
331
332 Setup extension local modules to examine whether demand importing
332 Setup extension local modules to examine whether demand importing
333 works as expected in "level > 1" case.
333 works as expected in "level > 1" case.
334
334
335 $ cat > $TESTTMP/absextroot/relimportee.py <<EOF
335 $ cat > $TESTTMP/absextroot/relimportee.py <<EOF
336 > detail = "this is absextroot.relimportee"
336 > detail = "this is absextroot.relimportee"
337 > EOF
337 > EOF
338 $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<EOF
338 $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<EOF
339 > from __future__ import absolute_import
339 > from __future__ import absolute_import
340 > from ... import relimportee
340 > from ... import relimportee
341 > detail = "this relimporter imports %r" % (relimportee.detail)
341 > detail = "this relimporter imports %r" % (relimportee.detail)
342 > EOF
342 > EOF
343
343
344 Setup modules, which actually import extension local modules at
344 Setup modules, which actually import extension local modules at
345 runtime.
345 runtime.
346
346
347 $ cat > $TESTTMP/absextroot/absolute.py << EOF
347 $ cat > $TESTTMP/absextroot/absolute.py << EOF
348 > from __future__ import absolute_import
348 > from __future__ import absolute_import
349 >
349 >
350 > # import extension local modules absolutely (level = 0)
350 > # import extension local modules absolutely (level = 0)
351 > from absextroot.xsub1.xsub2 import used, unused
351 > from absextroot.xsub1.xsub2 import used, unused
352 > from absextroot.xsub1.xsub2.called import func
352 > from absextroot.xsub1.xsub2.called import func
353 >
353 >
354 > def getresult():
354 > def getresult():
355 > result = []
355 > result = []
356 > result.append(used.detail)
356 > result.append(used.detail)
357 > result.append(func())
357 > result.append(func())
358 > return result
358 > return result
359 > EOF
359 > EOF
360
360
361 $ cat > $TESTTMP/absextroot/relative.py << EOF
361 $ cat > $TESTTMP/absextroot/relative.py << EOF
362 > from __future__ import absolute_import
362 > from __future__ import absolute_import
363 >
363 >
364 > # import extension local modules relatively (level == 1)
364 > # import extension local modules relatively (level == 1)
365 > from .xsub1.xsub2 import used, unused
365 > from .xsub1.xsub2 import used, unused
366 > from .xsub1.xsub2.called import func
366 > from .xsub1.xsub2.called import func
367 >
367 >
368 > # import a module, which implies "importing with level > 1"
368 > # import a module, which implies "importing with level > 1"
369 > from .xsub1.xsub2 import relimporter
369 > from .xsub1.xsub2 import relimporter
370 >
370 >
371 > def getresult():
371 > def getresult():
372 > result = []
372 > result = []
373 > result.append(used.detail)
373 > result.append(used.detail)
374 > result.append(func())
374 > result.append(func())
375 > result.append(relimporter.detail)
375 > result.append(relimporter.detail)
376 > return result
376 > return result
377 > EOF
377 > EOF
378
378
379 Setup main procedure of extension.
379 Setup main procedure of extension.
380
380
381 $ cat > $TESTTMP/absextroot/__init__.py <<EOF
381 $ cat > $TESTTMP/absextroot/__init__.py <<EOF
382 > from __future__ import absolute_import
382 > from __future__ import absolute_import
383 > from mercurial import cmdutil
383 > from mercurial import cmdutil
384 > cmdtable = {}
384 > cmdtable = {}
385 > command = cmdutil.command(cmdtable)
385 > command = cmdutil.command(cmdtable)
386 >
386 >
387 > # "absolute" and "relative" shouldn't be imported before actual
387 > # "absolute" and "relative" shouldn't be imported before actual
388 > # command execution, because (1) they import same modules, and (2)
388 > # command execution, because (1) they import same modules, and (2)
389 > # preceding import (= instantiate "demandmod" object instead of
389 > # preceding import (= instantiate "demandmod" object instead of
390 > # real "module" object) might hide problem of succeeding import.
390 > # real "module" object) might hide problem of succeeding import.
391 >
391 >
392 > @command('showabsolute', [], norepo=True)
392 > @command('showabsolute', [], norepo=True)
393 > def showabsolute(ui, *args, **opts):
393 > def showabsolute(ui, *args, **opts):
394 > from absextroot import absolute
394 > from absextroot import absolute
395 > ui.write('ABS: %s\n' % '\nABS: '.join(absolute.getresult()))
395 > ui.write('ABS: %s\n' % '\nABS: '.join(absolute.getresult()))
396 >
396 >
397 > @command('showrelative', [], norepo=True)
397 > @command('showrelative', [], norepo=True)
398 > def showrelative(ui, *args, **opts):
398 > def showrelative(ui, *args, **opts):
399 > from . import relative
399 > from . import relative
400 > ui.write('REL: %s\n' % '\nREL: '.join(relative.getresult()))
400 > ui.write('REL: %s\n' % '\nREL: '.join(relative.getresult()))
401 >
401 >
402 > # import modules from external library
402 > # import modules from external library
403 > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused
403 > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused
404 > from extlibroot.lsub1.lsub2.called import func as lfunc
404 > from extlibroot.lsub1.lsub2.called import func as lfunc
405 > from extlibroot.recursedown import absdetail, legacydetail
405 > from extlibroot.recursedown import absdetail, legacydetail
406 >
406 >
407 > def uisetup(ui):
407 > def uisetup(ui):
408 > result = []
408 > result = []
409 > result.append(lused.detail)
409 > result.append(lused.detail)
410 > result.append(lfunc())
410 > result.append(lfunc())
411 > result.append(absdetail)
411 > result.append(absdetail)
412 > result.append(legacydetail)
412 > result.append(legacydetail)
413 > ui.write('LIB: %s\n' % '\nLIB: '.join(result))
413 > ui.write('LIB: %s\n' % '\nLIB: '.join(result))
414 > EOF
414 > EOF
415
415
416 Examine module importing.
416 Examine module importing.
417
417
418 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute)
418 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute)
419 LIB: this is extlibroot.lsub1.lsub2.used
419 LIB: this is extlibroot.lsub1.lsub2.used
420 LIB: this is extlibroot.lsub1.lsub2.called.func()
420 LIB: this is extlibroot.lsub1.lsub2.called.func()
421 LIB: this is extlibroot.recursedown.abs.used
421 LIB: this is extlibroot.recursedown.abs.used
422 LIB: this is extlibroot.recursedown.legacy.used
422 LIB: this is extlibroot.recursedown.legacy.used
423 ABS: this is absextroot.xsub1.xsub2.used
423 ABS: this is absextroot.xsub1.xsub2.used
424 ABS: this is absextroot.xsub1.xsub2.called.func()
424 ABS: this is absextroot.xsub1.xsub2.called.func()
425
425
426 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative)
426 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative)
427 LIB: this is extlibroot.lsub1.lsub2.used
427 LIB: this is extlibroot.lsub1.lsub2.used
428 LIB: this is extlibroot.lsub1.lsub2.called.func()
428 LIB: this is extlibroot.lsub1.lsub2.called.func()
429 LIB: this is extlibroot.recursedown.abs.used
429 LIB: this is extlibroot.recursedown.abs.used
430 LIB: this is extlibroot.recursedown.legacy.used
430 LIB: this is extlibroot.recursedown.legacy.used
431 REL: this is absextroot.xsub1.xsub2.used
431 REL: this is absextroot.xsub1.xsub2.used
432 REL: this is absextroot.xsub1.xsub2.called.func()
432 REL: this is absextroot.xsub1.xsub2.called.func()
433 REL: this relimporter imports 'this is absextroot.relimportee'
433 REL: this relimporter imports 'this is absextroot.relimportee'
434
434
435 Examine whether sub-module is imported relatively as expected.
435 Examine whether sub-module is imported relatively as expected.
436
436
437 See also issue5208 for detail about example case on Python 3.x.
437 See also issue5208 for detail about example case on Python 3.x.
438
438
439 $ f -q $TESTTMP/extlibroot/lsub1/lsub2/notexist.py
439 $ f -q $TESTTMP/extlibroot/lsub1/lsub2/notexist.py
440 $TESTTMP/extlibroot/lsub1/lsub2/notexist.py: file not found
440 $TESTTMP/extlibroot/lsub1/lsub2/notexist.py: file not found
441
441
442 $ cat > $TESTTMP/notexist.py <<EOF
442 $ cat > $TESTTMP/notexist.py <<EOF
443 > text = 'notexist.py at root is loaded unintentionally\n'
443 > text = 'notexist.py at root is loaded unintentionally\n'
444 > EOF
444 > EOF
445
445
446 $ cat > $TESTTMP/checkrelativity.py <<EOF
446 $ cat > $TESTTMP/checkrelativity.py <<EOF
447 > from mercurial import cmdutil
447 > from mercurial import cmdutil
448 > cmdtable = {}
448 > cmdtable = {}
449 > command = cmdutil.command(cmdtable)
449 > command = cmdutil.command(cmdtable)
450 >
450 >
451 > # demand import avoids failure of importing notexist here
451 > # demand import avoids failure of importing notexist here
452 > import extlibroot.lsub1.lsub2.notexist
452 > import extlibroot.lsub1.lsub2.notexist
453 >
453 >
454 > @command('checkrelativity', [], norepo=True)
454 > @command('checkrelativity', [], norepo=True)
455 > def checkrelativity(ui, *args, **opts):
455 > def checkrelativity(ui, *args, **opts):
456 > try:
456 > try:
457 > ui.write(extlibroot.lsub1.lsub2.notexist.text)
457 > ui.write(extlibroot.lsub1.lsub2.notexist.text)
458 > return 1 # unintentional success
458 > return 1 # unintentional success
459 > except ImportError:
459 > except ImportError:
460 > pass # intentional failure
460 > pass # intentional failure
461 > EOF
461 > EOF
462
462
463 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.checkrelativity=$TESTTMP/checkrelativity.py checkrelativity)
463 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.checkrelativity=$TESTTMP/checkrelativity.py checkrelativity)
464
464
465 #endif
465 #endif
466
466
467 $ cd ..
467 $ cd ..
468
468
469 hide outer repo
469 hide outer repo
470 $ hg init
470 $ hg init
471
471
472 $ cat > empty.py <<EOF
472 $ cat > empty.py <<EOF
473 > '''empty cmdtable
473 > '''empty cmdtable
474 > '''
474 > '''
475 > cmdtable = {}
475 > cmdtable = {}
476 > EOF
476 > EOF
477 $ emptypath=`pwd`/empty.py
477 $ emptypath=`pwd`/empty.py
478 $ echo "empty = $emptypath" >> $HGRCPATH
478 $ echo "empty = $emptypath" >> $HGRCPATH
479 $ hg help empty
479 $ hg help empty
480 empty extension - empty cmdtable
480 empty extension - empty cmdtable
481
481
482 no commands defined
482 no commands defined
483
483
484
484
485 $ echo 'empty = !' >> $HGRCPATH
485 $ echo 'empty = !' >> $HGRCPATH
486
486
487 $ cat > debugextension.py <<EOF
487 $ cat > debugextension.py <<EOF
488 > '''only debugcommands
488 > '''only debugcommands
489 > '''
489 > '''
490 > from mercurial import cmdutil
490 > from mercurial import cmdutil
491 > cmdtable = {}
491 > cmdtable = {}
492 > command = cmdutil.command(cmdtable)
492 > command = cmdutil.command(cmdtable)
493 > @command('debugfoobar', [], 'hg debugfoobar')
493 > @command('debugfoobar', [], 'hg debugfoobar')
494 > def debugfoobar(ui, repo, *args, **opts):
494 > def debugfoobar(ui, repo, *args, **opts):
495 > "yet another debug command"
495 > "yet another debug command"
496 > pass
496 > pass
497 > @command('foo', [], 'hg foo')
497 > @command('foo', [], 'hg foo')
498 > def foo(ui, repo, *args, **opts):
498 > def foo(ui, repo, *args, **opts):
499 > """yet another foo command
499 > """yet another foo command
500 > This command has been DEPRECATED since forever.
500 > This command has been DEPRECATED since forever.
501 > """
501 > """
502 > pass
502 > pass
503 > EOF
503 > EOF
504 $ debugpath=`pwd`/debugextension.py
504 $ debugpath=`pwd`/debugextension.py
505 $ echo "debugextension = $debugpath" >> $HGRCPATH
505 $ echo "debugextension = $debugpath" >> $HGRCPATH
506
506
507 $ hg help debugextension
507 $ hg help debugextension
508 hg debugextensions
508 hg debugextensions
509
509
510 show information about active extensions
510 show information about active extensions
511
511
512 options:
512 options:
513
513
514 (some details hidden, use --verbose to show complete help)
514 (some details hidden, use --verbose to show complete help)
515
515
516
516
517 $ hg --verbose help debugextension
517 $ hg --verbose help debugextension
518 hg debugextensions
518 hg debugextensions
519
519
520 show information about active extensions
520 show information about active extensions
521
521
522 options:
522 options:
523
523
524 -T --template TEMPLATE display with template (EXPERIMENTAL)
524 -T --template TEMPLATE display with template (EXPERIMENTAL)
525
525
526 global options ([+] can be repeated):
526 global options ([+] can be repeated):
527
527
528 -R --repository REPO repository root directory or name of overlay bundle
528 -R --repository REPO repository root directory or name of overlay bundle
529 file
529 file
530 --cwd DIR change working directory
530 --cwd DIR change working directory
531 -y --noninteractive do not prompt, automatically pick the first choice for
531 -y --noninteractive do not prompt, automatically pick the first choice for
532 all prompts
532 all prompts
533 -q --quiet suppress output
533 -q --quiet suppress output
534 -v --verbose enable additional output
534 -v --verbose enable additional output
535 --config CONFIG [+] set/override config option (use 'section.name=value')
535 --config CONFIG [+] set/override config option (use 'section.name=value')
536 --debug enable debugging output
536 --debug enable debugging output
537 --debugger start debugger
537 --debugger start debugger
538 --encoding ENCODE set the charset encoding (default: ascii)
538 --encoding ENCODE set the charset encoding (default: ascii)
539 --encodingmode MODE set the charset encoding mode (default: strict)
539 --encodingmode MODE set the charset encoding mode (default: strict)
540 --traceback always print a traceback on exception
540 --traceback always print a traceback on exception
541 --time time how long the command takes
541 --time time how long the command takes
542 --profile print command execution profile
542 --profile print command execution profile
543 --version output version information and exit
543 --version output version information and exit
544 -h --help display help and exit
544 -h --help display help and exit
545 --hidden consider hidden changesets
545 --hidden consider hidden changesets
546
546
547
547
548
548
549
549
550
550
551
551
552 $ hg --debug help debugextension
552 $ hg --debug help debugextension
553 hg debugextensions
553 hg debugextensions
554
554
555 show information about active extensions
555 show information about active extensions
556
556
557 options:
557 options:
558
558
559 -T --template TEMPLATE display with template (EXPERIMENTAL)
559 -T --template TEMPLATE display with template (EXPERIMENTAL)
560
560
561 global options ([+] can be repeated):
561 global options ([+] can be repeated):
562
562
563 -R --repository REPO repository root directory or name of overlay bundle
563 -R --repository REPO repository root directory or name of overlay bundle
564 file
564 file
565 --cwd DIR change working directory
565 --cwd DIR change working directory
566 -y --noninteractive do not prompt, automatically pick the first choice for
566 -y --noninteractive do not prompt, automatically pick the first choice for
567 all prompts
567 all prompts
568 -q --quiet suppress output
568 -q --quiet suppress output
569 -v --verbose enable additional output
569 -v --verbose enable additional output
570 --config CONFIG [+] set/override config option (use 'section.name=value')
570 --config CONFIG [+] set/override config option (use 'section.name=value')
571 --debug enable debugging output
571 --debug enable debugging output
572 --debugger start debugger
572 --debugger start debugger
573 --encoding ENCODE set the charset encoding (default: ascii)
573 --encoding ENCODE set the charset encoding (default: ascii)
574 --encodingmode MODE set the charset encoding mode (default: strict)
574 --encodingmode MODE set the charset encoding mode (default: strict)
575 --traceback always print a traceback on exception
575 --traceback always print a traceback on exception
576 --time time how long the command takes
576 --time time how long the command takes
577 --profile print command execution profile
577 --profile print command execution profile
578 --version output version information and exit
578 --version output version information and exit
579 -h --help display help and exit
579 -h --help display help and exit
580 --hidden consider hidden changesets
580 --hidden consider hidden changesets
581
581
582
582
583
583
584
584
585
585
586 $ echo 'debugextension = !' >> $HGRCPATH
586 $ echo 'debugextension = !' >> $HGRCPATH
587
587
588 Asking for help about a deprecated extension should do something useful:
588 Asking for help about a deprecated extension should do something useful:
589
589
590 $ hg help glog
590 $ hg help glog
591 'glog' is provided by the following extension:
591 'glog' is provided by the following extension:
592
592
593 graphlog command to view revision graphs from a shell (DEPRECATED)
593 graphlog command to view revision graphs from a shell (DEPRECATED)
594
594
595 (use 'hg help extensions' for information on enabling extensions)
595 (use 'hg help extensions' for information on enabling extensions)
596
596
597 Extension module help vs command help:
597 Extension module help vs command help:
598
598
599 $ echo 'extdiff =' >> $HGRCPATH
599 $ echo 'extdiff =' >> $HGRCPATH
600 $ hg help extdiff
600 $ hg help extdiff
601 hg extdiff [OPT]... [FILE]...
601 hg extdiff [OPT]... [FILE]...
602
602
603 use external program to diff repository (or selected files)
603 use external program to diff repository (or selected files)
604
604
605 Show differences between revisions for the specified files, using an
605 Show differences between revisions for the specified files, using an
606 external program. The default program used is diff, with default options
606 external program. The default program used is diff, with default options
607 "-Npru".
607 "-Npru".
608
608
609 To select a different program, use the -p/--program option. The program
609 To select a different program, use the -p/--program option. The program
610 will be passed the names of two directories to compare. To pass additional
610 will be passed the names of two directories to compare. To pass additional
611 options to the program, use -o/--option. These will be passed before the
611 options to the program, use -o/--option. These will be passed before the
612 names of the directories to compare.
612 names of the directories to compare.
613
613
614 When two revision arguments are given, then changes are shown between
614 When two revision arguments are given, then changes are shown between
615 those revisions. If only one revision is specified then that revision is
615 those revisions. If only one revision is specified then that revision is
616 compared to the working directory, and, when no revisions are specified,
616 compared to the working directory, and, when no revisions are specified,
617 the working directory files are compared to its parent.
617 the working directory files are compared to its parent.
618
618
619 (use 'hg help -e extdiff' to show help for the extdiff extension)
619 (use 'hg help -e extdiff' to show help for the extdiff extension)
620
620
621 options ([+] can be repeated):
621 options ([+] can be repeated):
622
622
623 -p --program CMD comparison program to run
623 -p --program CMD comparison program to run
624 -o --option OPT [+] pass option to comparison program
624 -o --option OPT [+] pass option to comparison program
625 -r --rev REV [+] revision
625 -r --rev REV [+] revision
626 -c --change REV change made by revision
626 -c --change REV change made by revision
627 --patch compare patches for two revisions
627 --patch compare patches for two revisions
628 -I --include PATTERN [+] include names matching the given patterns
628 -I --include PATTERN [+] include names matching the given patterns
629 -X --exclude PATTERN [+] exclude names matching the given patterns
629 -X --exclude PATTERN [+] exclude names matching the given patterns
630 -S --subrepos recurse into subrepositories
630 -S --subrepos recurse into subrepositories
631
631
632 (some details hidden, use --verbose to show complete help)
632 (some details hidden, use --verbose to show complete help)
633
633
634
634
635
635
636
636
637
637
638
638
639
639
640
640
641
641
642
642
643 $ hg help --extension extdiff
643 $ hg help --extension extdiff
644 extdiff extension - command to allow external programs to compare revisions
644 extdiff extension - command to allow external programs to compare revisions
645
645
646 The extdiff Mercurial extension allows you to use external programs to compare
646 The extdiff Mercurial extension allows you to use external programs to compare
647 revisions, or revision with working directory. The external diff programs are
647 revisions, or revision with working directory. The external diff programs are
648 called with a configurable set of options and two non-option arguments: paths
648 called with a configurable set of options and two non-option arguments: paths
649 to directories containing snapshots of files to compare.
649 to directories containing snapshots of files to compare.
650
650
651 The extdiff extension also allows you to configure new diff commands, so you
651 The extdiff extension also allows you to configure new diff commands, so you
652 do not need to type 'hg extdiff -p kdiff3' always.
652 do not need to type 'hg extdiff -p kdiff3' always.
653
653
654 [extdiff]
654 [extdiff]
655 # add new command that runs GNU diff(1) in 'context diff' mode
655 # add new command that runs GNU diff(1) in 'context diff' mode
656 cdiff = gdiff -Nprc5
656 cdiff = gdiff -Nprc5
657 ## or the old way:
657 ## or the old way:
658 #cmd.cdiff = gdiff
658 #cmd.cdiff = gdiff
659 #opts.cdiff = -Nprc5
659 #opts.cdiff = -Nprc5
660
660
661 # add new command called meld, runs meld (no need to name twice). If
661 # add new command called meld, runs meld (no need to name twice). If
662 # the meld executable is not available, the meld tool in [merge-tools]
662 # the meld executable is not available, the meld tool in [merge-tools]
663 # will be used, if available
663 # will be used, if available
664 meld =
664 meld =
665
665
666 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
666 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
667 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
667 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
668 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
668 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
669 # your .vimrc
669 # your .vimrc
670 vimdiff = gvim -f "+next" \
670 vimdiff = gvim -f "+next" \
671 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
671 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
672
672
673 Tool arguments can include variables that are expanded at runtime:
673 Tool arguments can include variables that are expanded at runtime:
674
674
675 $parent1, $plabel1 - filename, descriptive label of first parent
675 $parent1, $plabel1 - filename, descriptive label of first parent
676 $child, $clabel - filename, descriptive label of child revision
676 $child, $clabel - filename, descriptive label of child revision
677 $parent2, $plabel2 - filename, descriptive label of second parent
677 $parent2, $plabel2 - filename, descriptive label of second parent
678 $root - repository root
678 $root - repository root
679 $parent is an alias for $parent1.
679 $parent is an alias for $parent1.
680
680
681 The extdiff extension will look in your [diff-tools] and [merge-tools]
681 The extdiff extension will look in your [diff-tools] and [merge-tools]
682 sections for diff tool arguments, when none are specified in [extdiff].
682 sections for diff tool arguments, when none are specified in [extdiff].
683
683
684 [extdiff]
684 [extdiff]
685 kdiff3 =
685 kdiff3 =
686
686
687 [diff-tools]
687 [diff-tools]
688 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
688 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
689
689
690 You can use -I/-X and list of file or directory names like normal 'hg diff'
690 You can use -I/-X and list of file or directory names like normal 'hg diff'
691 command. The extdiff extension makes snapshots of only needed files, so
691 command. The extdiff extension makes snapshots of only needed files, so
692 running the external diff program will actually be pretty fast (at least
692 running the external diff program will actually be pretty fast (at least
693 faster than having to compare the entire tree).
693 faster than having to compare the entire tree).
694
694
695 list of commands:
695 list of commands:
696
696
697 extdiff use external program to diff repository (or selected files)
697 extdiff use external program to diff repository (or selected files)
698
698
699 (use 'hg help -v -e extdiff' to show built-in aliases and global options)
699 (use 'hg help -v -e extdiff' to show built-in aliases and global options)
700
700
701
701
702
702
703
703
704
704
705
705
706
706
707
707
708
708
709
709
710
710
711
711
712
712
713
713
714
714
715
715
716 $ echo 'extdiff = !' >> $HGRCPATH
716 $ echo 'extdiff = !' >> $HGRCPATH
717
717
718 Test help topic with same name as extension
718 Test help topic with same name as extension
719
719
720 $ cat > multirevs.py <<EOF
720 $ cat > multirevs.py <<EOF
721 > from mercurial import cmdutil, commands
721 > from mercurial import cmdutil, commands
722 > cmdtable = {}
722 > cmdtable = {}
723 > command = cmdutil.command(cmdtable)
723 > command = cmdutil.command(cmdtable)
724 > """multirevs extension
724 > """multirevs extension
725 > Big multi-line module docstring."""
725 > Big multi-line module docstring."""
726 > @command('multirevs', [], 'ARG', norepo=True)
726 > @command('multirevs', [], 'ARG', norepo=True)
727 > def multirevs(ui, repo, arg, *args, **opts):
727 > def multirevs(ui, repo, arg, *args, **opts):
728 > """multirevs command"""
728 > """multirevs command"""
729 > pass
729 > pass
730 > EOF
730 > EOF
731 $ echo "multirevs = multirevs.py" >> $HGRCPATH
731 $ echo "multirevs = multirevs.py" >> $HGRCPATH
732
732
733 $ hg help multirevs
733 $ hg help multirevs
734 Specifying Multiple Revisions
734 Specifying Multiple Revisions
735 """""""""""""""""""""""""""""
735 """""""""""""""""""""""""""""
736
736
737 When Mercurial accepts more than one revision, they may be specified
737 When Mercurial accepts more than one revision, they may be specified
738 individually, or provided as a topologically continuous range, separated
738 individually, or provided as a topologically continuous range, separated
739 by the ":" character.
739 by the ":" character.
740
740
741 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
741 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
742 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
742 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
743 specified, it defaults to revision number 0. If END is not specified, it
743 specified, it defaults to revision number 0. If END is not specified, it
744 defaults to the tip. The range ":" thus means "all revisions".
744 defaults to the tip. The range ":" thus means "all revisions".
745
745
746 If BEGIN is greater than END, revisions are treated in reverse order.
746 If BEGIN is greater than END, revisions are treated in reverse order.
747
747
748 A range acts as a closed interval. This means that a range of 3:5 gives 3,
748 A range acts as a closed interval. This means that a range of 3:5 gives 3,
749 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
749 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
750
750
751 use 'hg help -c multirevs' to see help for the multirevs command
751 use 'hg help -c multirevs' to see help for the multirevs command
752
752
753
753
754
754
755
755
756
756
757
757
758 $ hg help -c multirevs
758 $ hg help -c multirevs
759 hg multirevs ARG
759 hg multirevs ARG
760
760
761 multirevs command
761 multirevs command
762
762
763 (some details hidden, use --verbose to show complete help)
763 (some details hidden, use --verbose to show complete help)
764
764
765
765
766
766
767 $ hg multirevs
767 $ hg multirevs
768 hg multirevs: invalid arguments
768 hg multirevs: invalid arguments
769 hg multirevs ARG
769 hg multirevs ARG
770
770
771 multirevs command
771 multirevs command
772
772
773 (use 'hg multirevs -h' to show more help)
773 (use 'hg multirevs -h' to show more help)
774 [255]
774 [255]
775
775
776
776
777
777
778 $ echo "multirevs = !" >> $HGRCPATH
778 $ echo "multirevs = !" >> $HGRCPATH
779
779
780 Issue811: Problem loading extensions twice (by site and by user)
780 Issue811: Problem loading extensions twice (by site and by user)
781
781
782 $ cat <<EOF >> $HGRCPATH
782 $ cat <<EOF >> $HGRCPATH
783 > mq =
783 > mq =
784 > strip =
784 > strip =
785 > hgext.mq =
785 > hgext.mq =
786 > hgext/mq =
786 > hgext/mq =
787 > EOF
787 > EOF
788
788
789 Show extensions:
789 Show extensions:
790 (note that mq force load strip, also checking it's not loaded twice)
790 (note that mq force load strip, also checking it's not loaded twice)
791
791
792 $ hg debugextensions
792 $ hg debugextensions
793 mq
793 mq
794 strip
794 strip
795
795
796 For extensions, which name matches one of its commands, help
796 For extensions, which name matches one of its commands, help
797 message should ask '-v -e' to get list of built-in aliases
797 message should ask '-v -e' to get list of built-in aliases
798 along with extension help itself
798 along with extension help itself
799
799
800 $ mkdir $TESTTMP/d
800 $ mkdir $TESTTMP/d
801 $ cat > $TESTTMP/d/dodo.py <<EOF
801 $ cat > $TESTTMP/d/dodo.py <<EOF
802 > """
802 > """
803 > This is an awesome 'dodo' extension. It does nothing and
803 > This is an awesome 'dodo' extension. It does nothing and
804 > writes 'Foo foo'
804 > writes 'Foo foo'
805 > """
805 > """
806 > from mercurial import cmdutil, commands
806 > from mercurial import cmdutil, commands
807 > cmdtable = {}
807 > cmdtable = {}
808 > command = cmdutil.command(cmdtable)
808 > command = cmdutil.command(cmdtable)
809 > @command('dodo', [], 'hg dodo')
809 > @command('dodo', [], 'hg dodo')
810 > def dodo(ui, *args, **kwargs):
810 > def dodo(ui, *args, **kwargs):
811 > """Does nothing"""
811 > """Does nothing"""
812 > ui.write("I do nothing. Yay\\n")
812 > ui.write("I do nothing. Yay\\n")
813 > @command('foofoo', [], 'hg foofoo')
813 > @command('foofoo', [], 'hg foofoo')
814 > def foofoo(ui, *args, **kwargs):
814 > def foofoo(ui, *args, **kwargs):
815 > """Writes 'Foo foo'"""
815 > """Writes 'Foo foo'"""
816 > ui.write("Foo foo\\n")
816 > ui.write("Foo foo\\n")
817 > EOF
817 > EOF
818 $ dodopath=$TESTTMP/d/dodo.py
818 $ dodopath=$TESTTMP/d/dodo.py
819
819
820 $ echo "dodo = $dodopath" >> $HGRCPATH
820 $ echo "dodo = $dodopath" >> $HGRCPATH
821
821
822 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
822 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
823 $ hg help -e dodo
823 $ hg help -e dodo
824 dodo extension -
824 dodo extension -
825
825
826 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
826 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
827
827
828 list of commands:
828 list of commands:
829
829
830 dodo Does nothing
830 dodo Does nothing
831 foofoo Writes 'Foo foo'
831 foofoo Writes 'Foo foo'
832
832
833 (use 'hg help -v -e dodo' to show built-in aliases and global options)
833 (use 'hg help -v -e dodo' to show built-in aliases and global options)
834
834
835 Make sure that '-v -e' prints list of built-in aliases along with
835 Make sure that '-v -e' prints list of built-in aliases along with
836 extension help itself
836 extension help itself
837 $ hg help -v -e dodo
837 $ hg help -v -e dodo
838 dodo extension -
838 dodo extension -
839
839
840 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
840 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
841
841
842 list of commands:
842 list of commands:
843
843
844 dodo Does nothing
844 dodo Does nothing
845 foofoo Writes 'Foo foo'
845 foofoo Writes 'Foo foo'
846
846
847 global options ([+] can be repeated):
847 global options ([+] can be repeated):
848
848
849 -R --repository REPO repository root directory or name of overlay bundle
849 -R --repository REPO repository root directory or name of overlay bundle
850 file
850 file
851 --cwd DIR change working directory
851 --cwd DIR change working directory
852 -y --noninteractive do not prompt, automatically pick the first choice for
852 -y --noninteractive do not prompt, automatically pick the first choice for
853 all prompts
853 all prompts
854 -q --quiet suppress output
854 -q --quiet suppress output
855 -v --verbose enable additional output
855 -v --verbose enable additional output
856 --config CONFIG [+] set/override config option (use 'section.name=value')
856 --config CONFIG [+] set/override config option (use 'section.name=value')
857 --debug enable debugging output
857 --debug enable debugging output
858 --debugger start debugger
858 --debugger start debugger
859 --encoding ENCODE set the charset encoding (default: ascii)
859 --encoding ENCODE set the charset encoding (default: ascii)
860 --encodingmode MODE set the charset encoding mode (default: strict)
860 --encodingmode MODE set the charset encoding mode (default: strict)
861 --traceback always print a traceback on exception
861 --traceback always print a traceback on exception
862 --time time how long the command takes
862 --time time how long the command takes
863 --profile print command execution profile
863 --profile print command execution profile
864 --version output version information and exit
864 --version output version information and exit
865 -h --help display help and exit
865 -h --help display help and exit
866 --hidden consider hidden changesets
866 --hidden consider hidden changesets
867
867
868 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
868 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
869 $ hg help -v dodo
869 $ hg help -v dodo
870 hg dodo
870 hg dodo
871
871
872 Does nothing
872 Does nothing
873
873
874 (use 'hg help -e dodo' to show help for the dodo extension)
874 (use 'hg help -e dodo' to show help for the dodo extension)
875
875
876 options:
876 options:
877
877
878 --mq operate on patch repository
878 --mq operate on patch repository
879
879
880 global options ([+] can be repeated):
880 global options ([+] can be repeated):
881
881
882 -R --repository REPO repository root directory or name of overlay bundle
882 -R --repository REPO repository root directory or name of overlay bundle
883 file
883 file
884 --cwd DIR change working directory
884 --cwd DIR change working directory
885 -y --noninteractive do not prompt, automatically pick the first choice for
885 -y --noninteractive do not prompt, automatically pick the first choice for
886 all prompts
886 all prompts
887 -q --quiet suppress output
887 -q --quiet suppress output
888 -v --verbose enable additional output
888 -v --verbose enable additional output
889 --config CONFIG [+] set/override config option (use 'section.name=value')
889 --config CONFIG [+] set/override config option (use 'section.name=value')
890 --debug enable debugging output
890 --debug enable debugging output
891 --debugger start debugger
891 --debugger start debugger
892 --encoding ENCODE set the charset encoding (default: ascii)
892 --encoding ENCODE set the charset encoding (default: ascii)
893 --encodingmode MODE set the charset encoding mode (default: strict)
893 --encodingmode MODE set the charset encoding mode (default: strict)
894 --traceback always print a traceback on exception
894 --traceback always print a traceback on exception
895 --time time how long the command takes
895 --time time how long the command takes
896 --profile print command execution profile
896 --profile print command execution profile
897 --version output version information and exit
897 --version output version information and exit
898 -h --help display help and exit
898 -h --help display help and exit
899 --hidden consider hidden changesets
899 --hidden consider hidden changesets
900
900
901 In case when extension name doesn't match any of its commands,
901 In case when extension name doesn't match any of its commands,
902 help message should ask for '-v' to get list of built-in aliases
902 help message should ask for '-v' to get list of built-in aliases
903 along with extension help
903 along with extension help
904 $ cat > $TESTTMP/d/dudu.py <<EOF
904 $ cat > $TESTTMP/d/dudu.py <<EOF
905 > """
905 > """
906 > This is an awesome 'dudu' extension. It does something and
906 > This is an awesome 'dudu' extension. It does something and
907 > also writes 'Beep beep'
907 > also writes 'Beep beep'
908 > """
908 > """
909 > from mercurial import cmdutil, commands
909 > from mercurial import cmdutil, commands
910 > cmdtable = {}
910 > cmdtable = {}
911 > command = cmdutil.command(cmdtable)
911 > command = cmdutil.command(cmdtable)
912 > @command('something', [], 'hg something')
912 > @command('something', [], 'hg something')
913 > def something(ui, *args, **kwargs):
913 > def something(ui, *args, **kwargs):
914 > """Does something"""
914 > """Does something"""
915 > ui.write("I do something. Yaaay\\n")
915 > ui.write("I do something. Yaaay\\n")
916 > @command('beep', [], 'hg beep')
916 > @command('beep', [], 'hg beep')
917 > def beep(ui, *args, **kwargs):
917 > def beep(ui, *args, **kwargs):
918 > """Writes 'Beep beep'"""
918 > """Writes 'Beep beep'"""
919 > ui.write("Beep beep\\n")
919 > ui.write("Beep beep\\n")
920 > EOF
920 > EOF
921 $ dudupath=$TESTTMP/d/dudu.py
921 $ dudupath=$TESTTMP/d/dudu.py
922
922
923 $ echo "dudu = $dudupath" >> $HGRCPATH
923 $ echo "dudu = $dudupath" >> $HGRCPATH
924
924
925 $ hg help -e dudu
925 $ hg help -e dudu
926 dudu extension -
926 dudu extension -
927
927
928 This is an awesome 'dudu' extension. It does something and also writes 'Beep
928 This is an awesome 'dudu' extension. It does something and also writes 'Beep
929 beep'
929 beep'
930
930
931 list of commands:
931 list of commands:
932
932
933 beep Writes 'Beep beep'
933 beep Writes 'Beep beep'
934 something Does something
934 something Does something
935
935
936 (use 'hg help -v dudu' to show built-in aliases and global options)
936 (use 'hg help -v dudu' to show built-in aliases and global options)
937
937
938 In case when extension name doesn't match any of its commands,
938 In case when extension name doesn't match any of its commands,
939 help options '-v' and '-v -e' should be equivalent
939 help options '-v' and '-v -e' should be equivalent
940 $ hg help -v dudu
940 $ hg help -v dudu
941 dudu extension -
941 dudu extension -
942
942
943 This is an awesome 'dudu' extension. It does something and also writes 'Beep
943 This is an awesome 'dudu' extension. It does something and also writes 'Beep
944 beep'
944 beep'
945
945
946 list of commands:
946 list of commands:
947
947
948 beep Writes 'Beep beep'
948 beep Writes 'Beep beep'
949 something Does something
949 something Does something
950
950
951 global options ([+] can be repeated):
951 global options ([+] can be repeated):
952
952
953 -R --repository REPO repository root directory or name of overlay bundle
953 -R --repository REPO repository root directory or name of overlay bundle
954 file
954 file
955 --cwd DIR change working directory
955 --cwd DIR change working directory
956 -y --noninteractive do not prompt, automatically pick the first choice for
956 -y --noninteractive do not prompt, automatically pick the first choice for
957 all prompts
957 all prompts
958 -q --quiet suppress output
958 -q --quiet suppress output
959 -v --verbose enable additional output
959 -v --verbose enable additional output
960 --config CONFIG [+] set/override config option (use 'section.name=value')
960 --config CONFIG [+] set/override config option (use 'section.name=value')
961 --debug enable debugging output
961 --debug enable debugging output
962 --debugger start debugger
962 --debugger start debugger
963 --encoding ENCODE set the charset encoding (default: ascii)
963 --encoding ENCODE set the charset encoding (default: ascii)
964 --encodingmode MODE set the charset encoding mode (default: strict)
964 --encodingmode MODE set the charset encoding mode (default: strict)
965 --traceback always print a traceback on exception
965 --traceback always print a traceback on exception
966 --time time how long the command takes
966 --time time how long the command takes
967 --profile print command execution profile
967 --profile print command execution profile
968 --version output version information and exit
968 --version output version information and exit
969 -h --help display help and exit
969 -h --help display help and exit
970 --hidden consider hidden changesets
970 --hidden consider hidden changesets
971
971
972 $ hg help -v -e dudu
972 $ hg help -v -e dudu
973 dudu extension -
973 dudu extension -
974
974
975 This is an awesome 'dudu' extension. It does something and also writes 'Beep
975 This is an awesome 'dudu' extension. It does something and also writes 'Beep
976 beep'
976 beep'
977
977
978 list of commands:
978 list of commands:
979
979
980 beep Writes 'Beep beep'
980 beep Writes 'Beep beep'
981 something Does something
981 something Does something
982
982
983 global options ([+] can be repeated):
983 global options ([+] can be repeated):
984
984
985 -R --repository REPO repository root directory or name of overlay bundle
985 -R --repository REPO repository root directory or name of overlay bundle
986 file
986 file
987 --cwd DIR change working directory
987 --cwd DIR change working directory
988 -y --noninteractive do not prompt, automatically pick the first choice for
988 -y --noninteractive do not prompt, automatically pick the first choice for
989 all prompts
989 all prompts
990 -q --quiet suppress output
990 -q --quiet suppress output
991 -v --verbose enable additional output
991 -v --verbose enable additional output
992 --config CONFIG [+] set/override config option (use 'section.name=value')
992 --config CONFIG [+] set/override config option (use 'section.name=value')
993 --debug enable debugging output
993 --debug enable debugging output
994 --debugger start debugger
994 --debugger start debugger
995 --encoding ENCODE set the charset encoding (default: ascii)
995 --encoding ENCODE set the charset encoding (default: ascii)
996 --encodingmode MODE set the charset encoding mode (default: strict)
996 --encodingmode MODE set the charset encoding mode (default: strict)
997 --traceback always print a traceback on exception
997 --traceback always print a traceback on exception
998 --time time how long the command takes
998 --time time how long the command takes
999 --profile print command execution profile
999 --profile print command execution profile
1000 --version output version information and exit
1000 --version output version information and exit
1001 -h --help display help and exit
1001 -h --help display help and exit
1002 --hidden consider hidden changesets
1002 --hidden consider hidden changesets
1003
1003
1004 Disabled extension commands:
1004 Disabled extension commands:
1005
1005
1006 $ ORGHGRCPATH=$HGRCPATH
1006 $ ORGHGRCPATH=$HGRCPATH
1007 $ HGRCPATH=
1007 $ HGRCPATH=
1008 $ export HGRCPATH
1008 $ export HGRCPATH
1009 $ hg help email
1009 $ hg help email
1010 'email' is provided by the following extension:
1010 'email' is provided by the following extension:
1011
1011
1012 patchbomb command to send changesets as (a series of) patch emails
1012 patchbomb command to send changesets as (a series of) patch emails
1013
1013
1014 (use 'hg help extensions' for information on enabling extensions)
1014 (use 'hg help extensions' for information on enabling extensions)
1015
1015
1016
1016
1017 $ hg qdel
1017 $ hg qdel
1018 hg: unknown command 'qdel'
1018 hg: unknown command 'qdel'
1019 'qdelete' is provided by the following extension:
1019 'qdelete' is provided by the following extension:
1020
1020
1021 mq manage a stack of patches
1021 mq manage a stack of patches
1022
1022
1023 (use 'hg help extensions' for information on enabling extensions)
1023 (use 'hg help extensions' for information on enabling extensions)
1024 [255]
1024 [255]
1025
1025
1026
1026
1027 $ hg churn
1027 $ hg churn
1028 hg: unknown command 'churn'
1028 hg: unknown command 'churn'
1029 'churn' is provided by the following extension:
1029 'churn' is provided by the following extension:
1030
1030
1031 churn command to display statistics about repository history
1031 churn command to display statistics about repository history
1032
1032
1033 (use 'hg help extensions' for information on enabling extensions)
1033 (use 'hg help extensions' for information on enabling extensions)
1034 [255]
1034 [255]
1035
1035
1036
1036
1037
1037
1038 Disabled extensions:
1038 Disabled extensions:
1039
1039
1040 $ hg help churn
1040 $ hg help churn
1041 churn extension - command to display statistics about repository history
1041 churn extension - command to display statistics about repository history
1042
1042
1043 (use 'hg help extensions' for information on enabling extensions)
1043 (use 'hg help extensions' for information on enabling extensions)
1044
1044
1045 $ hg help patchbomb
1045 $ hg help patchbomb
1046 patchbomb extension - command to send changesets as (a series of) patch emails
1046 patchbomb extension - command to send changesets as (a series of) patch emails
1047
1047
1048 The series is started off with a "[PATCH 0 of N]" introduction, which
1049 describes the series as a whole.
1050
1051 Each patch email has a Subject line of "[PATCH M of N] ...", using the first
1052 line of the changeset description as the subject text. The message contains
1053 two or three body parts:
1054
1055 - The changeset description.
1056 - [Optional] The result of running diffstat on the patch.
1057 - The patch itself, as generated by 'hg export'.
1058
1059 Each message refers to the first in the series using the In-Reply-To and
1060 References headers, so they will show up as a sequence in threaded mail and
1061 news readers, and in mail archives.
1062
1063 To configure other defaults, add a section like this to your configuration
1064 file:
1065
1066 [email]
1067 from = My Name <my@email>
1068 to = recipient1, recipient2, ...
1069 cc = cc1, cc2, ...
1070 bcc = bcc1, bcc2, ...
1071 reply-to = address1, address2, ...
1072
1073 Use "[patchbomb]" as configuration section name if you need to override global
1074 "[email]" address settings.
1075
1076 Then you can use the 'hg email' command to mail a series of changesets as a
1077 patchbomb.
1078
1079 You can also either configure the method option in the email section to be a
1080 sendmail compatible mailer or fill out the [smtp] section so that the
1081 patchbomb extension can automatically send patchbombs directly from the
1082 commandline. See the [email] and [smtp] sections in hgrc(5) for details.
1083
1084 By default, 'hg email' will prompt for a "To" or "CC" header if you do not
1085 supply one via configuration or the command line. You can override this to
1086 never prompt by configuring an empty value:
1087
1088 [email]
1089 cc =
1090
1091 You can control the default inclusion of an introduction message with the
1092 "patchbomb.intro" configuration option. The configuration is always
1093 overwritten by command line flags like --intro and --desc:
1094
1095 [patchbomb]
1096 intro=auto # include introduction message if more than 1 patch (default)
1097 intro=never # never include an introduction message
1098 intro=always # always include an introduction message
1099
1100 You can set patchbomb to always ask for confirmation by setting
1101 "patchbomb.confirm" to true.
1102
1048 (use 'hg help extensions' for information on enabling extensions)
1103 (use 'hg help extensions' for information on enabling extensions)
1049
1104
1050
1105
1051 Broken disabled extension and command:
1106 Broken disabled extension and command:
1052
1107
1053 $ mkdir hgext
1108 $ mkdir hgext
1054 $ echo > hgext/__init__.py
1109 $ echo > hgext/__init__.py
1055 $ cat > hgext/broken.py <<EOF
1110 $ cat > hgext/broken.py <<EOF
1056 > "broken extension'
1111 > "broken extension'
1057 > EOF
1112 > EOF
1058 $ cat > path.py <<EOF
1113 $ cat > path.py <<EOF
1059 > import os, sys
1114 > import os, sys
1060 > sys.path.insert(0, os.environ['HGEXTPATH'])
1115 > sys.path.insert(0, os.environ['HGEXTPATH'])
1061 > EOF
1116 > EOF
1062 $ HGEXTPATH=`pwd`
1117 $ HGEXTPATH=`pwd`
1063 $ export HGEXTPATH
1118 $ export HGEXTPATH
1064
1119
1065 $ hg --config extensions.path=./path.py help broken
1120 $ hg --config extensions.path=./path.py help broken
1066 broken extension - (no help text available)
1121 broken extension - (no help text available)
1067
1122
1068 (use 'hg help extensions' for information on enabling extensions)
1123 (use 'hg help extensions' for information on enabling extensions)
1069
1124
1070
1125
1071 $ cat > hgext/forest.py <<EOF
1126 $ cat > hgext/forest.py <<EOF
1072 > cmdtable = None
1127 > cmdtable = None
1073 > EOF
1128 > EOF
1074 $ hg --config extensions.path=./path.py help foo > /dev/null
1129 $ hg --config extensions.path=./path.py help foo > /dev/null
1075 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
1130 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
1076 abort: no such help topic: foo
1131 abort: no such help topic: foo
1077 (try 'hg help --keyword foo')
1132 (try 'hg help --keyword foo')
1078 [255]
1133 [255]
1079
1134
1080 $ cat > throw.py <<EOF
1135 $ cat > throw.py <<EOF
1081 > from mercurial import cmdutil, commands, util
1136 > from mercurial import cmdutil, commands, util
1082 > cmdtable = {}
1137 > cmdtable = {}
1083 > command = cmdutil.command(cmdtable)
1138 > command = cmdutil.command(cmdtable)
1084 > class Bogon(Exception): pass
1139 > class Bogon(Exception): pass
1085 > @command('throw', [], 'hg throw', norepo=True)
1140 > @command('throw', [], 'hg throw', norepo=True)
1086 > def throw(ui, **opts):
1141 > def throw(ui, **opts):
1087 > """throws an exception"""
1142 > """throws an exception"""
1088 > raise Bogon()
1143 > raise Bogon()
1089 > EOF
1144 > EOF
1090
1145
1091 No declared supported version, extension complains:
1146 No declared supported version, extension complains:
1092 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1147 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1093 ** Unknown exception encountered with possibly-broken third-party extension throw
1148 ** Unknown exception encountered with possibly-broken third-party extension throw
1094 ** which supports versions unknown of Mercurial.
1149 ** which supports versions unknown of Mercurial.
1095 ** Please disable throw and try your action again.
1150 ** Please disable throw and try your action again.
1096 ** If that fixes the bug please report it to the extension author.
1151 ** If that fixes the bug please report it to the extension author.
1097 ** Python * (glob)
1152 ** Python * (glob)
1098 ** Mercurial Distributed SCM * (glob)
1153 ** Mercurial Distributed SCM * (glob)
1099 ** Extensions loaded: throw
1154 ** Extensions loaded: throw
1100
1155
1101 empty declaration of supported version, extension complains:
1156 empty declaration of supported version, extension complains:
1102 $ echo "testedwith = ''" >> throw.py
1157 $ echo "testedwith = ''" >> throw.py
1103 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1158 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1104 ** Unknown exception encountered with possibly-broken third-party extension throw
1159 ** Unknown exception encountered with possibly-broken third-party extension throw
1105 ** which supports versions unknown of Mercurial.
1160 ** which supports versions unknown of Mercurial.
1106 ** Please disable throw and try your action again.
1161 ** Please disable throw and try your action again.
1107 ** If that fixes the bug please report it to the extension author.
1162 ** If that fixes the bug please report it to the extension author.
1108 ** Python * (glob)
1163 ** Python * (glob)
1109 ** Mercurial Distributed SCM (*) (glob)
1164 ** Mercurial Distributed SCM (*) (glob)
1110 ** Extensions loaded: throw
1165 ** Extensions loaded: throw
1111
1166
1112 If the extension specifies a buglink, show that:
1167 If the extension specifies a buglink, show that:
1113 $ echo 'buglink = "http://example.com/bts"' >> throw.py
1168 $ echo 'buglink = "http://example.com/bts"' >> throw.py
1114 $ rm -f throw.pyc throw.pyo
1169 $ rm -f throw.pyc throw.pyo
1115 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1170 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1116 ** Unknown exception encountered with possibly-broken third-party extension throw
1171 ** Unknown exception encountered with possibly-broken third-party extension throw
1117 ** which supports versions unknown of Mercurial.
1172 ** which supports versions unknown of Mercurial.
1118 ** Please disable throw and try your action again.
1173 ** Please disable throw and try your action again.
1119 ** If that fixes the bug please report it to http://example.com/bts
1174 ** If that fixes the bug please report it to http://example.com/bts
1120 ** Python * (glob)
1175 ** Python * (glob)
1121 ** Mercurial Distributed SCM (*) (glob)
1176 ** Mercurial Distributed SCM (*) (glob)
1122 ** Extensions loaded: throw
1177 ** Extensions loaded: throw
1123
1178
1124 If the extensions declare outdated versions, accuse the older extension first:
1179 If the extensions declare outdated versions, accuse the older extension first:
1125 $ echo "from mercurial import util" >> older.py
1180 $ echo "from mercurial import util" >> older.py
1126 $ echo "util.version = lambda:'2.2'" >> older.py
1181 $ echo "util.version = lambda:'2.2'" >> older.py
1127 $ echo "testedwith = '1.9.3'" >> older.py
1182 $ echo "testedwith = '1.9.3'" >> older.py
1128 $ echo "testedwith = '2.1.1'" >> throw.py
1183 $ echo "testedwith = '2.1.1'" >> throw.py
1129 $ rm -f throw.pyc throw.pyo
1184 $ rm -f throw.pyc throw.pyo
1130 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1185 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1131 > throw 2>&1 | egrep '^\*\*'
1186 > throw 2>&1 | egrep '^\*\*'
1132 ** Unknown exception encountered with possibly-broken third-party extension older
1187 ** Unknown exception encountered with possibly-broken third-party extension older
1133 ** which supports versions 1.9 of Mercurial.
1188 ** which supports versions 1.9 of Mercurial.
1134 ** Please disable older and try your action again.
1189 ** Please disable older and try your action again.
1135 ** If that fixes the bug please report it to the extension author.
1190 ** If that fixes the bug please report it to the extension author.
1136 ** Python * (glob)
1191 ** Python * (glob)
1137 ** Mercurial Distributed SCM (version 2.2)
1192 ** Mercurial Distributed SCM (version 2.2)
1138 ** Extensions loaded: throw, older
1193 ** Extensions loaded: throw, older
1139
1194
1140 One extension only tested with older, one only with newer versions:
1195 One extension only tested with older, one only with newer versions:
1141 $ echo "util.version = lambda:'2.1'" >> older.py
1196 $ echo "util.version = lambda:'2.1'" >> older.py
1142 $ rm -f older.pyc older.pyo
1197 $ rm -f older.pyc older.pyo
1143 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1198 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1144 > throw 2>&1 | egrep '^\*\*'
1199 > throw 2>&1 | egrep '^\*\*'
1145 ** Unknown exception encountered with possibly-broken third-party extension older
1200 ** Unknown exception encountered with possibly-broken third-party extension older
1146 ** which supports versions 1.9 of Mercurial.
1201 ** which supports versions 1.9 of Mercurial.
1147 ** Please disable older and try your action again.
1202 ** Please disable older and try your action again.
1148 ** If that fixes the bug please report it to the extension author.
1203 ** If that fixes the bug please report it to the extension author.
1149 ** Python * (glob)
1204 ** Python * (glob)
1150 ** Mercurial Distributed SCM (version 2.1)
1205 ** Mercurial Distributed SCM (version 2.1)
1151 ** Extensions loaded: throw, older
1206 ** Extensions loaded: throw, older
1152
1207
1153 Older extension is tested with current version, the other only with newer:
1208 Older extension is tested with current version, the other only with newer:
1154 $ echo "util.version = lambda:'1.9.3'" >> older.py
1209 $ echo "util.version = lambda:'1.9.3'" >> older.py
1155 $ rm -f older.pyc older.pyo
1210 $ rm -f older.pyc older.pyo
1156 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1211 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1157 > throw 2>&1 | egrep '^\*\*'
1212 > throw 2>&1 | egrep '^\*\*'
1158 ** Unknown exception encountered with possibly-broken third-party extension throw
1213 ** Unknown exception encountered with possibly-broken third-party extension throw
1159 ** which supports versions 2.1 of Mercurial.
1214 ** which supports versions 2.1 of Mercurial.
1160 ** Please disable throw and try your action again.
1215 ** Please disable throw and try your action again.
1161 ** If that fixes the bug please report it to http://example.com/bts
1216 ** If that fixes the bug please report it to http://example.com/bts
1162 ** Python * (glob)
1217 ** Python * (glob)
1163 ** Mercurial Distributed SCM (version 1.9.3)
1218 ** Mercurial Distributed SCM (version 1.9.3)
1164 ** Extensions loaded: throw, older
1219 ** Extensions loaded: throw, older
1165
1220
1166 Ability to point to a different point
1221 Ability to point to a different point
1167 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1222 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1168 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
1223 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
1169 ** unknown exception encountered, please report by visiting
1224 ** unknown exception encountered, please report by visiting
1170 ** Your Local Goat Lenders
1225 ** Your Local Goat Lenders
1171 ** Python * (glob)
1226 ** Python * (glob)
1172 ** Mercurial Distributed SCM (*) (glob)
1227 ** Mercurial Distributed SCM (*) (glob)
1173 ** Extensions loaded: throw, older
1228 ** Extensions loaded: throw, older
1174
1229
1175 Declare the version as supporting this hg version, show regular bts link:
1230 Declare the version as supporting this hg version, show regular bts link:
1176 $ hgver=`hg debuginstall -T '{hgver}'`
1231 $ hgver=`hg debuginstall -T '{hgver}'`
1177 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
1232 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
1178 $ if [ -z "$hgver" ]; then
1233 $ if [ -z "$hgver" ]; then
1179 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
1234 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
1180 > fi
1235 > fi
1181 $ rm -f throw.pyc throw.pyo
1236 $ rm -f throw.pyc throw.pyo
1182 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1237 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1183 ** unknown exception encountered, please report by visiting
1238 ** unknown exception encountered, please report by visiting
1184 ** https://mercurial-scm.org/wiki/BugTracker
1239 ** https://mercurial-scm.org/wiki/BugTracker
1185 ** Python * (glob)
1240 ** Python * (glob)
1186 ** Mercurial Distributed SCM (*) (glob)
1241 ** Mercurial Distributed SCM (*) (glob)
1187 ** Extensions loaded: throw
1242 ** Extensions loaded: throw
1188
1243
1189 Patch version is ignored during compatibility check
1244 Patch version is ignored during compatibility check
1190 $ echo "testedwith = '3.2'" >> throw.py
1245 $ echo "testedwith = '3.2'" >> throw.py
1191 $ echo "util.version = lambda:'3.2.2'" >> throw.py
1246 $ echo "util.version = lambda:'3.2.2'" >> throw.py
1192 $ rm -f throw.pyc throw.pyo
1247 $ rm -f throw.pyc throw.pyo
1193 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1248 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1194 ** unknown exception encountered, please report by visiting
1249 ** unknown exception encountered, please report by visiting
1195 ** https://mercurial-scm.org/wiki/BugTracker
1250 ** https://mercurial-scm.org/wiki/BugTracker
1196 ** Python * (glob)
1251 ** Python * (glob)
1197 ** Mercurial Distributed SCM (*) (glob)
1252 ** Mercurial Distributed SCM (*) (glob)
1198 ** Extensions loaded: throw
1253 ** Extensions loaded: throw
1199
1254
1200 Test version number support in 'hg version':
1255 Test version number support in 'hg version':
1201 $ echo '__version__ = (1, 2, 3)' >> throw.py
1256 $ echo '__version__ = (1, 2, 3)' >> throw.py
1202 $ rm -f throw.pyc throw.pyo
1257 $ rm -f throw.pyc throw.pyo
1203 $ hg version -v
1258 $ hg version -v
1204 Mercurial Distributed SCM (version *) (glob)
1259 Mercurial Distributed SCM (version *) (glob)
1205 (see https://mercurial-scm.org for more information)
1260 (see https://mercurial-scm.org for more information)
1206
1261
1207 Copyright (C) 2005-* Matt Mackall and others (glob)
1262 Copyright (C) 2005-* Matt Mackall and others (glob)
1208 This is free software; see the source for copying conditions. There is NO
1263 This is free software; see the source for copying conditions. There is NO
1209 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1264 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1210
1265
1211 Enabled extensions:
1266 Enabled extensions:
1212
1267
1213
1268
1214 $ hg version -v --config extensions.throw=throw.py
1269 $ hg version -v --config extensions.throw=throw.py
1215 Mercurial Distributed SCM (version *) (glob)
1270 Mercurial Distributed SCM (version *) (glob)
1216 (see https://mercurial-scm.org for more information)
1271 (see https://mercurial-scm.org for more information)
1217
1272
1218 Copyright (C) 2005-* Matt Mackall and others (glob)
1273 Copyright (C) 2005-* Matt Mackall and others (glob)
1219 This is free software; see the source for copying conditions. There is NO
1274 This is free software; see the source for copying conditions. There is NO
1220 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1275 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1221
1276
1222 Enabled extensions:
1277 Enabled extensions:
1223
1278
1224 throw external 1.2.3
1279 throw external 1.2.3
1225 $ echo 'getversion = lambda: "1.twentythree"' >> throw.py
1280 $ echo 'getversion = lambda: "1.twentythree"' >> throw.py
1226 $ rm -f throw.pyc throw.pyo
1281 $ rm -f throw.pyc throw.pyo
1227 $ hg version -v --config extensions.throw=throw.py --config extensions.strip=
1282 $ hg version -v --config extensions.throw=throw.py --config extensions.strip=
1228 Mercurial Distributed SCM (version *) (glob)
1283 Mercurial Distributed SCM (version *) (glob)
1229 (see https://mercurial-scm.org for more information)
1284 (see https://mercurial-scm.org for more information)
1230
1285
1231 Copyright (C) 2005-* Matt Mackall and others (glob)
1286 Copyright (C) 2005-* Matt Mackall and others (glob)
1232 This is free software; see the source for copying conditions. There is NO
1287 This is free software; see the source for copying conditions. There is NO
1233 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1288 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1234
1289
1235 Enabled extensions:
1290 Enabled extensions:
1236
1291
1237 throw external 1.twentythree
1292 throw external 1.twentythree
1238 strip internal
1293 strip internal
1239
1294
1240 $ hg version -q --config extensions.throw=throw.py
1295 $ hg version -q --config extensions.throw=throw.py
1241 Mercurial Distributed SCM (version *) (glob)
1296 Mercurial Distributed SCM (version *) (glob)
1242
1297
1243 Test JSON output of version:
1298 Test JSON output of version:
1244
1299
1245 $ hg version -Tjson
1300 $ hg version -Tjson
1246 [
1301 [
1247 {
1302 {
1248 "extensions": [],
1303 "extensions": [],
1249 "ver": "*" (glob)
1304 "ver": "*" (glob)
1250 }
1305 }
1251 ]
1306 ]
1252
1307
1253 $ hg version --config extensions.throw=throw.py -Tjson
1308 $ hg version --config extensions.throw=throw.py -Tjson
1254 [
1309 [
1255 {
1310 {
1256 "extensions": [{"bundled": false, "name": "throw", "ver": "1.twentythree"}],
1311 "extensions": [{"bundled": false, "name": "throw", "ver": "1.twentythree"}],
1257 "ver": "3.2.2"
1312 "ver": "3.2.2"
1258 }
1313 }
1259 ]
1314 ]
1260
1315
1261 $ hg version --config extensions.strip= -Tjson
1316 $ hg version --config extensions.strip= -Tjson
1262 [
1317 [
1263 {
1318 {
1264 "extensions": [{"bundled": true, "name": "strip", "ver": null}],
1319 "extensions": [{"bundled": true, "name": "strip", "ver": null}],
1265 "ver": "*" (glob)
1320 "ver": "*" (glob)
1266 }
1321 }
1267 ]
1322 ]
1268
1323
1269 Test template output of version:
1324 Test template output of version:
1270
1325
1271 $ hg version --config extensions.throw=throw.py --config extensions.strip= \
1326 $ hg version --config extensions.throw=throw.py --config extensions.strip= \
1272 > -T'{extensions % "{name} {pad(ver, 16)} ({if(bundled, "internal", "external")})\n"}'
1327 > -T'{extensions % "{name} {pad(ver, 16)} ({if(bundled, "internal", "external")})\n"}'
1273 throw 1.twentythree (external)
1328 throw 1.twentythree (external)
1274 strip (internal)
1329 strip (internal)
1275
1330
1276 Refuse to load extensions with minimum version requirements
1331 Refuse to load extensions with minimum version requirements
1277
1332
1278 $ cat > minversion1.py << EOF
1333 $ cat > minversion1.py << EOF
1279 > from mercurial import util
1334 > from mercurial import util
1280 > util.version = lambda: '3.5.2'
1335 > util.version = lambda: '3.5.2'
1281 > minimumhgversion = '3.6'
1336 > minimumhgversion = '3.6'
1282 > EOF
1337 > EOF
1283 $ hg --config extensions.minversion=minversion1.py version
1338 $ hg --config extensions.minversion=minversion1.py version
1284 (third party extension minversion requires version 3.6 or newer of Mercurial; disabling)
1339 (third party extension minversion requires version 3.6 or newer of Mercurial; disabling)
1285 Mercurial Distributed SCM (version 3.5.2)
1340 Mercurial Distributed SCM (version 3.5.2)
1286 (see https://mercurial-scm.org for more information)
1341 (see https://mercurial-scm.org for more information)
1287
1342
1288 Copyright (C) 2005-* Matt Mackall and others (glob)
1343 Copyright (C) 2005-* Matt Mackall and others (glob)
1289 This is free software; see the source for copying conditions. There is NO
1344 This is free software; see the source for copying conditions. There is NO
1290 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1345 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1291
1346
1292 $ cat > minversion2.py << EOF
1347 $ cat > minversion2.py << EOF
1293 > from mercurial import util
1348 > from mercurial import util
1294 > util.version = lambda: '3.6'
1349 > util.version = lambda: '3.6'
1295 > minimumhgversion = '3.7'
1350 > minimumhgversion = '3.7'
1296 > EOF
1351 > EOF
1297 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1352 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1298 (third party extension minversion requires version 3.7 or newer of Mercurial; disabling)
1353 (third party extension minversion requires version 3.7 or newer of Mercurial; disabling)
1299
1354
1300 Can load version that is only off by point release
1355 Can load version that is only off by point release
1301
1356
1302 $ cat > minversion2.py << EOF
1357 $ cat > minversion2.py << EOF
1303 > from mercurial import util
1358 > from mercurial import util
1304 > util.version = lambda: '3.6.1'
1359 > util.version = lambda: '3.6.1'
1305 > minimumhgversion = '3.6'
1360 > minimumhgversion = '3.6'
1306 > EOF
1361 > EOF
1307 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1362 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1308 [1]
1363 [1]
1309
1364
1310 Can load minimum version identical to current
1365 Can load minimum version identical to current
1311
1366
1312 $ cat > minversion3.py << EOF
1367 $ cat > minversion3.py << EOF
1313 > from mercurial import util
1368 > from mercurial import util
1314 > util.version = lambda: '3.5'
1369 > util.version = lambda: '3.5'
1315 > minimumhgversion = '3.5'
1370 > minimumhgversion = '3.5'
1316 > EOF
1371 > EOF
1317 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1372 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1318 [1]
1373 [1]
1319
1374
1320 Restore HGRCPATH
1375 Restore HGRCPATH
1321
1376
1322 $ HGRCPATH=$ORGHGRCPATH
1377 $ HGRCPATH=$ORGHGRCPATH
1323 $ export HGRCPATH
1378 $ export HGRCPATH
1324
1379
1325 Commands handling multiple repositories at a time should invoke only
1380 Commands handling multiple repositories at a time should invoke only
1326 "reposetup()" of extensions enabling in the target repository.
1381 "reposetup()" of extensions enabling in the target repository.
1327
1382
1328 $ mkdir reposetup-test
1383 $ mkdir reposetup-test
1329 $ cd reposetup-test
1384 $ cd reposetup-test
1330
1385
1331 $ cat > $TESTTMP/reposetuptest.py <<EOF
1386 $ cat > $TESTTMP/reposetuptest.py <<EOF
1332 > from mercurial import extensions
1387 > from mercurial import extensions
1333 > def reposetup(ui, repo):
1388 > def reposetup(ui, repo):
1334 > ui.write('reposetup() for %s\n' % (repo.root))
1389 > ui.write('reposetup() for %s\n' % (repo.root))
1335 > ui.flush()
1390 > ui.flush()
1336 > EOF
1391 > EOF
1337 $ hg init src
1392 $ hg init src
1338 $ echo a > src/a
1393 $ echo a > src/a
1339 $ hg -R src commit -Am '#0 at src/a'
1394 $ hg -R src commit -Am '#0 at src/a'
1340 adding a
1395 adding a
1341 $ echo '[extensions]' >> src/.hg/hgrc
1396 $ echo '[extensions]' >> src/.hg/hgrc
1342 $ echo '# enable extension locally' >> src/.hg/hgrc
1397 $ echo '# enable extension locally' >> src/.hg/hgrc
1343 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1398 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1344 $ hg -R src status
1399 $ hg -R src status
1345 reposetup() for $TESTTMP/reposetup-test/src (glob)
1400 reposetup() for $TESTTMP/reposetup-test/src (glob)
1346
1401
1347 $ hg clone -U src clone-dst1
1402 $ hg clone -U src clone-dst1
1348 reposetup() for $TESTTMP/reposetup-test/src (glob)
1403 reposetup() for $TESTTMP/reposetup-test/src (glob)
1349 $ hg init push-dst1
1404 $ hg init push-dst1
1350 $ hg -q -R src push push-dst1
1405 $ hg -q -R src push push-dst1
1351 reposetup() for $TESTTMP/reposetup-test/src (glob)
1406 reposetup() for $TESTTMP/reposetup-test/src (glob)
1352 $ hg init pull-src1
1407 $ hg init pull-src1
1353 $ hg -q -R pull-src1 pull src
1408 $ hg -q -R pull-src1 pull src
1354 reposetup() for $TESTTMP/reposetup-test/src (glob)
1409 reposetup() for $TESTTMP/reposetup-test/src (glob)
1355
1410
1356 $ cat <<EOF >> $HGRCPATH
1411 $ cat <<EOF >> $HGRCPATH
1357 > [extensions]
1412 > [extensions]
1358 > # disable extension globally and explicitly
1413 > # disable extension globally and explicitly
1359 > reposetuptest = !
1414 > reposetuptest = !
1360 > EOF
1415 > EOF
1361 $ hg clone -U src clone-dst2
1416 $ hg clone -U src clone-dst2
1362 reposetup() for $TESTTMP/reposetup-test/src (glob)
1417 reposetup() for $TESTTMP/reposetup-test/src (glob)
1363 $ hg init push-dst2
1418 $ hg init push-dst2
1364 $ hg -q -R src push push-dst2
1419 $ hg -q -R src push push-dst2
1365 reposetup() for $TESTTMP/reposetup-test/src (glob)
1420 reposetup() for $TESTTMP/reposetup-test/src (glob)
1366 $ hg init pull-src2
1421 $ hg init pull-src2
1367 $ hg -q -R pull-src2 pull src
1422 $ hg -q -R pull-src2 pull src
1368 reposetup() for $TESTTMP/reposetup-test/src (glob)
1423 reposetup() for $TESTTMP/reposetup-test/src (glob)
1369
1424
1370 $ cat <<EOF >> $HGRCPATH
1425 $ cat <<EOF >> $HGRCPATH
1371 > [extensions]
1426 > [extensions]
1372 > # enable extension globally
1427 > # enable extension globally
1373 > reposetuptest = $TESTTMP/reposetuptest.py
1428 > reposetuptest = $TESTTMP/reposetuptest.py
1374 > EOF
1429 > EOF
1375 $ hg clone -U src clone-dst3
1430 $ hg clone -U src clone-dst3
1376 reposetup() for $TESTTMP/reposetup-test/src (glob)
1431 reposetup() for $TESTTMP/reposetup-test/src (glob)
1377 reposetup() for $TESTTMP/reposetup-test/clone-dst3 (glob)
1432 reposetup() for $TESTTMP/reposetup-test/clone-dst3 (glob)
1378 $ hg init push-dst3
1433 $ hg init push-dst3
1379 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1434 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1380 $ hg -q -R src push push-dst3
1435 $ hg -q -R src push push-dst3
1381 reposetup() for $TESTTMP/reposetup-test/src (glob)
1436 reposetup() for $TESTTMP/reposetup-test/src (glob)
1382 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1437 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1383 $ hg init pull-src3
1438 $ hg init pull-src3
1384 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1439 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1385 $ hg -q -R pull-src3 pull src
1440 $ hg -q -R pull-src3 pull src
1386 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1441 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1387 reposetup() for $TESTTMP/reposetup-test/src (glob)
1442 reposetup() for $TESTTMP/reposetup-test/src (glob)
1388
1443
1389 $ echo '[extensions]' >> src/.hg/hgrc
1444 $ echo '[extensions]' >> src/.hg/hgrc
1390 $ echo '# disable extension locally' >> src/.hg/hgrc
1445 $ echo '# disable extension locally' >> src/.hg/hgrc
1391 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1446 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1392 $ hg clone -U src clone-dst4
1447 $ hg clone -U src clone-dst4
1393 reposetup() for $TESTTMP/reposetup-test/clone-dst4 (glob)
1448 reposetup() for $TESTTMP/reposetup-test/clone-dst4 (glob)
1394 $ hg init push-dst4
1449 $ hg init push-dst4
1395 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1450 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1396 $ hg -q -R src push push-dst4
1451 $ hg -q -R src push push-dst4
1397 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1452 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1398 $ hg init pull-src4
1453 $ hg init pull-src4
1399 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1454 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1400 $ hg -q -R pull-src4 pull src
1455 $ hg -q -R pull-src4 pull src
1401 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1456 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1402
1457
1403 disabling in command line overlays with all configuration
1458 disabling in command line overlays with all configuration
1404 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1459 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1405 $ hg --config extensions.reposetuptest=! init push-dst5
1460 $ hg --config extensions.reposetuptest=! init push-dst5
1406 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1461 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1407 $ hg --config extensions.reposetuptest=! init pull-src5
1462 $ hg --config extensions.reposetuptest=! init pull-src5
1408 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1463 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1409
1464
1410 $ cat <<EOF >> $HGRCPATH
1465 $ cat <<EOF >> $HGRCPATH
1411 > [extensions]
1466 > [extensions]
1412 > # disable extension globally and explicitly
1467 > # disable extension globally and explicitly
1413 > reposetuptest = !
1468 > reposetuptest = !
1414 > EOF
1469 > EOF
1415 $ hg init parent
1470 $ hg init parent
1416 $ hg init parent/sub1
1471 $ hg init parent/sub1
1417 $ echo 1 > parent/sub1/1
1472 $ echo 1 > parent/sub1/1
1418 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1473 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1419 adding 1
1474 adding 1
1420 $ hg init parent/sub2
1475 $ hg init parent/sub2
1421 $ hg init parent/sub2/sub21
1476 $ hg init parent/sub2/sub21
1422 $ echo 21 > parent/sub2/sub21/21
1477 $ echo 21 > parent/sub2/sub21/21
1423 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1478 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1424 adding 21
1479 adding 21
1425 $ cat > parent/sub2/.hgsub <<EOF
1480 $ cat > parent/sub2/.hgsub <<EOF
1426 > sub21 = sub21
1481 > sub21 = sub21
1427 > EOF
1482 > EOF
1428 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1483 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1429 adding .hgsub
1484 adding .hgsub
1430 $ hg init parent/sub3
1485 $ hg init parent/sub3
1431 $ echo 3 > parent/sub3/3
1486 $ echo 3 > parent/sub3/3
1432 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1487 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1433 adding 3
1488 adding 3
1434 $ cat > parent/.hgsub <<EOF
1489 $ cat > parent/.hgsub <<EOF
1435 > sub1 = sub1
1490 > sub1 = sub1
1436 > sub2 = sub2
1491 > sub2 = sub2
1437 > sub3 = sub3
1492 > sub3 = sub3
1438 > EOF
1493 > EOF
1439 $ hg -R parent commit -Am '#0 at parent'
1494 $ hg -R parent commit -Am '#0 at parent'
1440 adding .hgsub
1495 adding .hgsub
1441 $ echo '[extensions]' >> parent/.hg/hgrc
1496 $ echo '[extensions]' >> parent/.hg/hgrc
1442 $ echo '# enable extension locally' >> parent/.hg/hgrc
1497 $ echo '# enable extension locally' >> parent/.hg/hgrc
1443 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1498 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1444 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1499 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1445 $ hg -R parent status -S -A
1500 $ hg -R parent status -S -A
1446 reposetup() for $TESTTMP/reposetup-test/parent (glob)
1501 reposetup() for $TESTTMP/reposetup-test/parent (glob)
1447 reposetup() for $TESTTMP/reposetup-test/parent/sub2 (glob)
1502 reposetup() for $TESTTMP/reposetup-test/parent/sub2 (glob)
1448 C .hgsub
1503 C .hgsub
1449 C .hgsubstate
1504 C .hgsubstate
1450 C sub1/1
1505 C sub1/1
1451 C sub2/.hgsub
1506 C sub2/.hgsub
1452 C sub2/.hgsubstate
1507 C sub2/.hgsubstate
1453 C sub2/sub21/21
1508 C sub2/sub21/21
1454 C sub3/3
1509 C sub3/3
1455
1510
1456 $ cd ..
1511 $ cd ..
1457
1512
1458 Test compatibility with extension commands that don't use @command (issue5137)
1513 Test compatibility with extension commands that don't use @command (issue5137)
1459
1514
1460 $ hg init deprecated
1515 $ hg init deprecated
1461 $ cd deprecated
1516 $ cd deprecated
1462
1517
1463 $ cat <<EOF > deprecatedcmd.py
1518 $ cat <<EOF > deprecatedcmd.py
1464 > def deprecatedcmd(repo, ui):
1519 > def deprecatedcmd(repo, ui):
1465 > pass
1520 > pass
1466 > cmdtable = {
1521 > cmdtable = {
1467 > 'deprecatedcmd': (deprecatedcmd, [], ''),
1522 > 'deprecatedcmd': (deprecatedcmd, [], ''),
1468 > }
1523 > }
1469 > EOF
1524 > EOF
1470 $ cat <<EOF > .hg/hgrc
1525 $ cat <<EOF > .hg/hgrc
1471 > [extensions]
1526 > [extensions]
1472 > deprecatedcmd = `pwd`/deprecatedcmd.py
1527 > deprecatedcmd = `pwd`/deprecatedcmd.py
1473 > mq = !
1528 > mq = !
1474 > hgext.mq = !
1529 > hgext.mq = !
1475 > hgext/mq = !
1530 > hgext/mq = !
1476 > [alias]
1531 > [alias]
1477 > deprecatedalias = deprecatedcmd
1532 > deprecatedalias = deprecatedcmd
1478 > EOF
1533 > EOF
1479
1534
1480 $ hg deprecatedcmd
1535 $ hg deprecatedcmd
1481 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedcmd'
1536 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedcmd'
1482 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1537 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1483
1538
1484 $ hg deprecatedalias
1539 $ hg deprecatedalias
1485 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedalias'
1540 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedalias'
1486 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1541 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1487
1542
1488 no warning unless command is executed:
1543 no warning unless command is executed:
1489
1544
1490 $ hg paths
1545 $ hg paths
1491
1546
1492 but mq iterates over command table:
1547 but mq iterates over command table:
1493
1548
1494 $ hg --config extensions.mq= paths
1549 $ hg --config extensions.mq= paths
1495 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedcmd'
1550 devel-warn: missing attribute 'norepo', use @command decorator to register 'deprecatedcmd'
1496 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1551 (compatibility will be dropped after Mercurial-3.8, update your code.) at: * (glob)
1497
1552
1498 $ cd ..
1553 $ cd ..
1499
1554
1500 Test synopsis and docstring extending
1555 Test synopsis and docstring extending
1501
1556
1502 $ hg init exthelp
1557 $ hg init exthelp
1503 $ cat > exthelp.py <<EOF
1558 $ cat > exthelp.py <<EOF
1504 > from mercurial import commands, extensions
1559 > from mercurial import commands, extensions
1505 > def exbookmarks(orig, *args, **opts):
1560 > def exbookmarks(orig, *args, **opts):
1506 > return orig(*args, **opts)
1561 > return orig(*args, **opts)
1507 > def uisetup(ui):
1562 > def uisetup(ui):
1508 > synopsis = ' GREPME [--foo] [-x]'
1563 > synopsis = ' GREPME [--foo] [-x]'
1509 > docstring = '''
1564 > docstring = '''
1510 > GREPME make sure that this is in the help!
1565 > GREPME make sure that this is in the help!
1511 > '''
1566 > '''
1512 > extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
1567 > extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
1513 > synopsis, docstring)
1568 > synopsis, docstring)
1514 > EOF
1569 > EOF
1515 $ abspath=`pwd`/exthelp.py
1570 $ abspath=`pwd`/exthelp.py
1516 $ echo '[extensions]' >> $HGRCPATH
1571 $ echo '[extensions]' >> $HGRCPATH
1517 $ echo "exthelp = $abspath" >> $HGRCPATH
1572 $ echo "exthelp = $abspath" >> $HGRCPATH
1518 $ cd exthelp
1573 $ cd exthelp
1519 $ hg help bookmarks | grep GREPME
1574 $ hg help bookmarks | grep GREPME
1520 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1575 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1521 GREPME make sure that this is in the help!
1576 GREPME make sure that this is in the help!
1522
1577
@@ -1,412 +1,415 b''
1 Create configuration
1 Create configuration
2
2
3 $ echo "[ui]" >> $HGRCPATH
3 $ echo "[ui]" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
4 $ echo "interactive=true" >> $HGRCPATH
5
5
6 help record (no record)
6 help record (no record)
7
7
8 $ hg help record
8 $ hg help record
9 record extension - commands to interactively select changes for
9 record extension - commands to interactively select changes for
10 commit/qrefresh (DEPRECATED)
10 commit/qrefresh (DEPRECATED)
11
11
12 The feature provided by this extension has been moved into core Mercurial as
13 'hg commit --interactive'.
14
12 (use 'hg help extensions' for information on enabling extensions)
15 (use 'hg help extensions' for information on enabling extensions)
13
16
14 help qrecord (no record)
17 help qrecord (no record)
15
18
16 $ hg help qrecord
19 $ hg help qrecord
17 'qrecord' is provided by the following extension:
20 'qrecord' is provided by the following extension:
18
21
19 record commands to interactively select changes for commit/qrefresh
22 record commands to interactively select changes for commit/qrefresh
20 (DEPRECATED)
23 (DEPRECATED)
21
24
22 (use 'hg help extensions' for information on enabling extensions)
25 (use 'hg help extensions' for information on enabling extensions)
23
26
24 $ echo "[extensions]" >> $HGRCPATH
27 $ echo "[extensions]" >> $HGRCPATH
25 $ echo "record=" >> $HGRCPATH
28 $ echo "record=" >> $HGRCPATH
26
29
27 help record (record)
30 help record (record)
28
31
29 $ hg help record
32 $ hg help record
30 hg record [OPTION]... [FILE]...
33 hg record [OPTION]... [FILE]...
31
34
32 interactively select changes to commit
35 interactively select changes to commit
33
36
34 If a list of files is omitted, all changes reported by 'hg status' will be
37 If a list of files is omitted, all changes reported by 'hg status' will be
35 candidates for recording.
38 candidates for recording.
36
39
37 See 'hg help dates' for a list of formats valid for -d/--date.
40 See 'hg help dates' for a list of formats valid for -d/--date.
38
41
39 You will be prompted for whether to record changes to each modified file,
42 You will be prompted for whether to record changes to each modified file,
40 and for files with multiple changes, for each change to use. For each
43 and for files with multiple changes, for each change to use. For each
41 query, the following responses are possible:
44 query, the following responses are possible:
42
45
43 y - record this change
46 y - record this change
44 n - skip this change
47 n - skip this change
45 e - edit this change manually
48 e - edit this change manually
46
49
47 s - skip remaining changes to this file
50 s - skip remaining changes to this file
48 f - record remaining changes to this file
51 f - record remaining changes to this file
49
52
50 d - done, skip remaining changes and files
53 d - done, skip remaining changes and files
51 a - record all changes to all remaining files
54 a - record all changes to all remaining files
52 q - quit, recording no changes
55 q - quit, recording no changes
53
56
54 ? - display help
57 ? - display help
55
58
56 This command is not available when committing a merge.
59 This command is not available when committing a merge.
57
60
58 (use 'hg help -e record' to show help for the record extension)
61 (use 'hg help -e record' to show help for the record extension)
59
62
60 options ([+] can be repeated):
63 options ([+] can be repeated):
61
64
62 -A --addremove mark new/missing files as added/removed before
65 -A --addremove mark new/missing files as added/removed before
63 committing
66 committing
64 --close-branch mark a branch head as closed
67 --close-branch mark a branch head as closed
65 --amend amend the parent of the working directory
68 --amend amend the parent of the working directory
66 -s --secret use the secret phase for committing
69 -s --secret use the secret phase for committing
67 -e --edit invoke editor on commit messages
70 -e --edit invoke editor on commit messages
68 -I --include PATTERN [+] include names matching the given patterns
71 -I --include PATTERN [+] include names matching the given patterns
69 -X --exclude PATTERN [+] exclude names matching the given patterns
72 -X --exclude PATTERN [+] exclude names matching the given patterns
70 -m --message TEXT use text as commit message
73 -m --message TEXT use text as commit message
71 -l --logfile FILE read commit message from file
74 -l --logfile FILE read commit message from file
72 -d --date DATE record the specified date as commit date
75 -d --date DATE record the specified date as commit date
73 -u --user USER record the specified user as committer
76 -u --user USER record the specified user as committer
74 -S --subrepos recurse into subrepositories
77 -S --subrepos recurse into subrepositories
75 -w --ignore-all-space ignore white space when comparing lines
78 -w --ignore-all-space ignore white space when comparing lines
76 -b --ignore-space-change ignore changes in the amount of white space
79 -b --ignore-space-change ignore changes in the amount of white space
77 -B --ignore-blank-lines ignore changes whose lines are all blank
80 -B --ignore-blank-lines ignore changes whose lines are all blank
78
81
79 (some details hidden, use --verbose to show complete help)
82 (some details hidden, use --verbose to show complete help)
80
83
81 help (no mq, so no qrecord)
84 help (no mq, so no qrecord)
82
85
83 $ hg help qrecord
86 $ hg help qrecord
84 hg qrecord [OPTION]... PATCH [FILE]...
87 hg qrecord [OPTION]... PATCH [FILE]...
85
88
86 interactively record a new patch
89 interactively record a new patch
87
90
88 See 'hg help qnew' & 'hg help record' for more information and usage.
91 See 'hg help qnew' & 'hg help record' for more information and usage.
89
92
90 (some details hidden, use --verbose to show complete help)
93 (some details hidden, use --verbose to show complete help)
91
94
92 $ hg init a
95 $ hg init a
93
96
94 qrecord (mq not present)
97 qrecord (mq not present)
95
98
96 $ hg -R a qrecord
99 $ hg -R a qrecord
97 hg qrecord: invalid arguments
100 hg qrecord: invalid arguments
98 hg qrecord [OPTION]... PATCH [FILE]...
101 hg qrecord [OPTION]... PATCH [FILE]...
99
102
100 interactively record a new patch
103 interactively record a new patch
101
104
102 (use 'hg qrecord -h' to show more help)
105 (use 'hg qrecord -h' to show more help)
103 [255]
106 [255]
104
107
105 qrecord patch (mq not present)
108 qrecord patch (mq not present)
106
109
107 $ hg -R a qrecord patch
110 $ hg -R a qrecord patch
108 abort: 'mq' extension not loaded
111 abort: 'mq' extension not loaded
109 [255]
112 [255]
110
113
111 help (bad mq)
114 help (bad mq)
112
115
113 $ echo "mq=nonexistent" >> $HGRCPATH
116 $ echo "mq=nonexistent" >> $HGRCPATH
114 $ hg help qrecord
117 $ hg help qrecord
115 *** failed to import extension mq from nonexistent: [Errno *] * (glob)
118 *** failed to import extension mq from nonexistent: [Errno *] * (glob)
116 hg qrecord [OPTION]... PATCH [FILE]...
119 hg qrecord [OPTION]... PATCH [FILE]...
117
120
118 interactively record a new patch
121 interactively record a new patch
119
122
120 See 'hg help qnew' & 'hg help record' for more information and usage.
123 See 'hg help qnew' & 'hg help record' for more information and usage.
121
124
122 (some details hidden, use --verbose to show complete help)
125 (some details hidden, use --verbose to show complete help)
123
126
124 help (mq present)
127 help (mq present)
125
128
126 $ sed 's/mq=nonexistent/mq=/' $HGRCPATH > hgrc.tmp
129 $ sed 's/mq=nonexistent/mq=/' $HGRCPATH > hgrc.tmp
127 $ mv hgrc.tmp $HGRCPATH
130 $ mv hgrc.tmp $HGRCPATH
128
131
129 $ hg help qrecord
132 $ hg help qrecord
130 hg qrecord [OPTION]... PATCH [FILE]...
133 hg qrecord [OPTION]... PATCH [FILE]...
131
134
132 interactively record a new patch
135 interactively record a new patch
133
136
134 See 'hg help qnew' & 'hg help record' for more information and usage.
137 See 'hg help qnew' & 'hg help record' for more information and usage.
135
138
136 options ([+] can be repeated):
139 options ([+] can be repeated):
137
140
138 -e --edit invoke editor on commit messages
141 -e --edit invoke editor on commit messages
139 -g --git use git extended diff format
142 -g --git use git extended diff format
140 -U --currentuser add "From: <current user>" to patch
143 -U --currentuser add "From: <current user>" to patch
141 -u --user USER add "From: <USER>" to patch
144 -u --user USER add "From: <USER>" to patch
142 -D --currentdate add "Date: <current date>" to patch
145 -D --currentdate add "Date: <current date>" to patch
143 -d --date DATE add "Date: <DATE>" to patch
146 -d --date DATE add "Date: <DATE>" to patch
144 -I --include PATTERN [+] include names matching the given patterns
147 -I --include PATTERN [+] include names matching the given patterns
145 -X --exclude PATTERN [+] exclude names matching the given patterns
148 -X --exclude PATTERN [+] exclude names matching the given patterns
146 -m --message TEXT use text as commit message
149 -m --message TEXT use text as commit message
147 -l --logfile FILE read commit message from file
150 -l --logfile FILE read commit message from file
148 -w --ignore-all-space ignore white space when comparing lines
151 -w --ignore-all-space ignore white space when comparing lines
149 -b --ignore-space-change ignore changes in the amount of white space
152 -b --ignore-space-change ignore changes in the amount of white space
150 -B --ignore-blank-lines ignore changes whose lines are all blank
153 -B --ignore-blank-lines ignore changes whose lines are all blank
151 --mq operate on patch repository
154 --mq operate on patch repository
152
155
153 (some details hidden, use --verbose to show complete help)
156 (some details hidden, use --verbose to show complete help)
154
157
155 $ cd a
158 $ cd a
156
159
157 Base commit
160 Base commit
158
161
159 $ cat > 1.txt <<EOF
162 $ cat > 1.txt <<EOF
160 > 1
163 > 1
161 > 2
164 > 2
162 > 3
165 > 3
163 > 4
166 > 4
164 > 5
167 > 5
165 > EOF
168 > EOF
166 $ cat > 2.txt <<EOF
169 $ cat > 2.txt <<EOF
167 > a
170 > a
168 > b
171 > b
169 > c
172 > c
170 > d
173 > d
171 > e
174 > e
172 > f
175 > f
173 > EOF
176 > EOF
174
177
175 $ mkdir dir
178 $ mkdir dir
176 $ cat > dir/a.txt <<EOF
179 $ cat > dir/a.txt <<EOF
177 > hello world
180 > hello world
178 >
181 >
179 > someone
182 > someone
180 > up
183 > up
181 > there
184 > there
182 > loves
185 > loves
183 > me
186 > me
184 > EOF
187 > EOF
185
188
186 $ hg add 1.txt 2.txt dir/a.txt
189 $ hg add 1.txt 2.txt dir/a.txt
187 $ hg commit -m 'initial checkin'
190 $ hg commit -m 'initial checkin'
188
191
189 Changing files
192 Changing files
190
193
191 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
194 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
192 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
195 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
193 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
196 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
194
197
195 $ mv -f 1.txt.new 1.txt
198 $ mv -f 1.txt.new 1.txt
196 $ mv -f 2.txt.new 2.txt
199 $ mv -f 2.txt.new 2.txt
197 $ mv -f dir/a.txt.new dir/a.txt
200 $ mv -f dir/a.txt.new dir/a.txt
198
201
199 Whole diff
202 Whole diff
200
203
201 $ hg diff --nodates
204 $ hg diff --nodates
202 diff -r 1057167b20ef 1.txt
205 diff -r 1057167b20ef 1.txt
203 --- a/1.txt
206 --- a/1.txt
204 +++ b/1.txt
207 +++ b/1.txt
205 @@ -1,5 +1,5 @@
208 @@ -1,5 +1,5 @@
206 1
209 1
207 -2
210 -2
208 +2 2
211 +2 2
209 3
212 3
210 -4
213 -4
211 +4 4
214 +4 4
212 5
215 5
213 diff -r 1057167b20ef 2.txt
216 diff -r 1057167b20ef 2.txt
214 --- a/2.txt
217 --- a/2.txt
215 +++ b/2.txt
218 +++ b/2.txt
216 @@ -1,5 +1,5 @@
219 @@ -1,5 +1,5 @@
217 a
220 a
218 -b
221 -b
219 +b b
222 +b b
220 c
223 c
221 d
224 d
222 e
225 e
223 diff -r 1057167b20ef dir/a.txt
226 diff -r 1057167b20ef dir/a.txt
224 --- a/dir/a.txt
227 --- a/dir/a.txt
225 +++ b/dir/a.txt
228 +++ b/dir/a.txt
226 @@ -1,4 +1,4 @@
229 @@ -1,4 +1,4 @@
227 -hello world
230 -hello world
228 +hello world!
231 +hello world!
229
232
230 someone
233 someone
231 up
234 up
232
235
233 qrecord with bad patch name, should abort before prompting
236 qrecord with bad patch name, should abort before prompting
234
237
235 $ hg qrecord .hg
238 $ hg qrecord .hg
236 abort: patch name cannot begin with ".hg"
239 abort: patch name cannot begin with ".hg"
237 [255]
240 [255]
238
241
239 qrecord a.patch
242 qrecord a.patch
240
243
241 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
244 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
242 > y
245 > y
243 > y
246 > y
244 > n
247 > n
245 > y
248 > y
246 > y
249 > y
247 > n
250 > n
248 > EOF
251 > EOF
249 diff --git a/1.txt b/1.txt
252 diff --git a/1.txt b/1.txt
250 2 hunks, 2 lines changed
253 2 hunks, 2 lines changed
251 examine changes to '1.txt'? [Ynesfdaq?] y
254 examine changes to '1.txt'? [Ynesfdaq?] y
252
255
253 @@ -1,3 +1,3 @@
256 @@ -1,3 +1,3 @@
254 1
257 1
255 -2
258 -2
256 +2 2
259 +2 2
257 3
260 3
258 record change 1/4 to '1.txt'? [Ynesfdaq?] y
261 record change 1/4 to '1.txt'? [Ynesfdaq?] y
259
262
260 @@ -3,3 +3,3 @@
263 @@ -3,3 +3,3 @@
261 3
264 3
262 -4
265 -4
263 +4 4
266 +4 4
264 5
267 5
265 record change 2/4 to '1.txt'? [Ynesfdaq?] n
268 record change 2/4 to '1.txt'? [Ynesfdaq?] n
266
269
267 diff --git a/2.txt b/2.txt
270 diff --git a/2.txt b/2.txt
268 1 hunks, 1 lines changed
271 1 hunks, 1 lines changed
269 examine changes to '2.txt'? [Ynesfdaq?] y
272 examine changes to '2.txt'? [Ynesfdaq?] y
270
273
271 @@ -1,5 +1,5 @@
274 @@ -1,5 +1,5 @@
272 a
275 a
273 -b
276 -b
274 +b b
277 +b b
275 c
278 c
276 d
279 d
277 e
280 e
278 record change 3/4 to '2.txt'? [Ynesfdaq?] y
281 record change 3/4 to '2.txt'? [Ynesfdaq?] y
279
282
280 diff --git a/dir/a.txt b/dir/a.txt
283 diff --git a/dir/a.txt b/dir/a.txt
281 1 hunks, 1 lines changed
284 1 hunks, 1 lines changed
282 examine changes to 'dir/a.txt'? [Ynesfdaq?] n
285 examine changes to 'dir/a.txt'? [Ynesfdaq?] n
283
286
284
287
285 After qrecord a.patch 'tip'"
288 After qrecord a.patch 'tip'"
286
289
287 $ hg tip -p
290 $ hg tip -p
288 changeset: 1:5d1ca63427ee
291 changeset: 1:5d1ca63427ee
289 tag: a.patch
292 tag: a.patch
290 tag: qbase
293 tag: qbase
291 tag: qtip
294 tag: qtip
292 tag: tip
295 tag: tip
293 user: test
296 user: test
294 date: Thu Jan 01 00:00:00 1970 +0000
297 date: Thu Jan 01 00:00:00 1970 +0000
295 summary: aaa
298 summary: aaa
296
299
297 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
300 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
298 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
301 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
299 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
302 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
300 @@ -1,5 +1,5 @@
303 @@ -1,5 +1,5 @@
301 1
304 1
302 -2
305 -2
303 +2 2
306 +2 2
304 3
307 3
305 4
308 4
306 5
309 5
307 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
310 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
308 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
311 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
309 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
312 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
310 @@ -1,5 +1,5 @@
313 @@ -1,5 +1,5 @@
311 a
314 a
312 -b
315 -b
313 +b b
316 +b b
314 c
317 c
315 d
318 d
316 e
319 e
317
320
318
321
319 After qrecord a.patch 'diff'"
322 After qrecord a.patch 'diff'"
320
323
321 $ hg diff --nodates
324 $ hg diff --nodates
322 diff -r 5d1ca63427ee 1.txt
325 diff -r 5d1ca63427ee 1.txt
323 --- a/1.txt
326 --- a/1.txt
324 +++ b/1.txt
327 +++ b/1.txt
325 @@ -1,5 +1,5 @@
328 @@ -1,5 +1,5 @@
326 1
329 1
327 2 2
330 2 2
328 3
331 3
329 -4
332 -4
330 +4 4
333 +4 4
331 5
334 5
332 diff -r 5d1ca63427ee dir/a.txt
335 diff -r 5d1ca63427ee dir/a.txt
333 --- a/dir/a.txt
336 --- a/dir/a.txt
334 +++ b/dir/a.txt
337 +++ b/dir/a.txt
335 @@ -1,4 +1,4 @@
338 @@ -1,4 +1,4 @@
336 -hello world
339 -hello world
337 +hello world!
340 +hello world!
338
341
339 someone
342 someone
340 up
343 up
341
344
342 qrecord b.patch
345 qrecord b.patch
343
346
344 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
347 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
345 > y
348 > y
346 > y
349 > y
347 > y
350 > y
348 > y
351 > y
349 > EOF
352 > EOF
350 diff --git a/1.txt b/1.txt
353 diff --git a/1.txt b/1.txt
351 1 hunks, 1 lines changed
354 1 hunks, 1 lines changed
352 examine changes to '1.txt'? [Ynesfdaq?] y
355 examine changes to '1.txt'? [Ynesfdaq?] y
353
356
354 @@ -1,5 +1,5 @@
357 @@ -1,5 +1,5 @@
355 1
358 1
356 2 2
359 2 2
357 3
360 3
358 -4
361 -4
359 +4 4
362 +4 4
360 5
363 5
361 record change 1/2 to '1.txt'? [Ynesfdaq?] y
364 record change 1/2 to '1.txt'? [Ynesfdaq?] y
362
365
363 diff --git a/dir/a.txt b/dir/a.txt
366 diff --git a/dir/a.txt b/dir/a.txt
364 1 hunks, 1 lines changed
367 1 hunks, 1 lines changed
365 examine changes to 'dir/a.txt'? [Ynesfdaq?] y
368 examine changes to 'dir/a.txt'? [Ynesfdaq?] y
366
369
367 @@ -1,4 +1,4 @@
370 @@ -1,4 +1,4 @@
368 -hello world
371 -hello world
369 +hello world!
372 +hello world!
370
373
371 someone
374 someone
372 up
375 up
373 record change 2/2 to 'dir/a.txt'? [Ynesfdaq?] y
376 record change 2/2 to 'dir/a.txt'? [Ynesfdaq?] y
374
377
375
378
376 After qrecord b.patch 'tip'
379 After qrecord b.patch 'tip'
377
380
378 $ hg tip -p
381 $ hg tip -p
379 changeset: 2:b056198bf878
382 changeset: 2:b056198bf878
380 tag: b.patch
383 tag: b.patch
381 tag: qtip
384 tag: qtip
382 tag: tip
385 tag: tip
383 user: test
386 user: test
384 date: Thu Jan 01 00:00:00 1970 +0000
387 date: Thu Jan 01 00:00:00 1970 +0000
385 summary: bbb
388 summary: bbb
386
389
387 diff -r 5d1ca63427ee -r b056198bf878 1.txt
390 diff -r 5d1ca63427ee -r b056198bf878 1.txt
388 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
391 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
389 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
392 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
390 @@ -1,5 +1,5 @@
393 @@ -1,5 +1,5 @@
391 1
394 1
392 2 2
395 2 2
393 3
396 3
394 -4
397 -4
395 +4 4
398 +4 4
396 5
399 5
397 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
400 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
398 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
401 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
399 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
402 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
400 @@ -1,4 +1,4 @@
403 @@ -1,4 +1,4 @@
401 -hello world
404 -hello world
402 +hello world!
405 +hello world!
403
406
404 someone
407 someone
405 up
408 up
406
409
407
410
408 After qrecord b.patch 'diff'
411 After qrecord b.patch 'diff'
409
412
410 $ hg diff --nodates
413 $ hg diff --nodates
411
414
412 $ cd ..
415 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now