##// END OF EJS Templates
dispatch: print the version of the extension being blamed in a bug report...
Matt Harbison -
r46563:c26cb33e default
parent child Browse files
Show More
@@ -1,1333 +1,1335 b''
1 # dispatch.py - command dispatching for mercurial
1 # dispatch.py - command dispatching 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, print_function
8 from __future__ import absolute_import, print_function
9
9
10 import errno
10 import errno
11 import getopt
11 import getopt
12 import io
12 import io
13 import os
13 import os
14 import pdb
14 import pdb
15 import re
15 import re
16 import signal
16 import signal
17 import sys
17 import sys
18 import traceback
18 import traceback
19
19
20
20
21 from .i18n import _
21 from .i18n import _
22 from .pycompat import getattr
22 from .pycompat import getattr
23
23
24 from hgdemandimport import tracing
24 from hgdemandimport import tracing
25
25
26 from . import (
26 from . import (
27 cmdutil,
27 cmdutil,
28 color,
28 color,
29 commands,
29 commands,
30 demandimport,
30 demandimport,
31 encoding,
31 encoding,
32 error,
32 error,
33 extensions,
33 extensions,
34 fancyopts,
34 fancyopts,
35 help,
35 help,
36 hg,
36 hg,
37 hook,
37 hook,
38 localrepo,
38 localrepo,
39 profiling,
39 profiling,
40 pycompat,
40 pycompat,
41 rcutil,
41 rcutil,
42 registrar,
42 registrar,
43 requirements as requirementsmod,
43 requirements as requirementsmod,
44 scmutil,
44 scmutil,
45 ui as uimod,
45 ui as uimod,
46 util,
46 util,
47 vfs,
47 vfs,
48 )
48 )
49
49
50 from .utils import (
50 from .utils import (
51 procutil,
51 procutil,
52 stringutil,
52 stringutil,
53 )
53 )
54
54
55
55
56 class request(object):
56 class request(object):
57 def __init__(
57 def __init__(
58 self,
58 self,
59 args,
59 args,
60 ui=None,
60 ui=None,
61 repo=None,
61 repo=None,
62 fin=None,
62 fin=None,
63 fout=None,
63 fout=None,
64 ferr=None,
64 ferr=None,
65 fmsg=None,
65 fmsg=None,
66 prereposetups=None,
66 prereposetups=None,
67 ):
67 ):
68 self.args = args
68 self.args = args
69 self.ui = ui
69 self.ui = ui
70 self.repo = repo
70 self.repo = repo
71
71
72 # input/output/error streams
72 # input/output/error streams
73 self.fin = fin
73 self.fin = fin
74 self.fout = fout
74 self.fout = fout
75 self.ferr = ferr
75 self.ferr = ferr
76 # separate stream for status/error messages
76 # separate stream for status/error messages
77 self.fmsg = fmsg
77 self.fmsg = fmsg
78
78
79 # remember options pre-parsed by _earlyparseopts()
79 # remember options pre-parsed by _earlyparseopts()
80 self.earlyoptions = {}
80 self.earlyoptions = {}
81
81
82 # reposetups which run before extensions, useful for chg to pre-fill
82 # reposetups which run before extensions, useful for chg to pre-fill
83 # low-level repo state (for example, changelog) before extensions.
83 # low-level repo state (for example, changelog) before extensions.
84 self.prereposetups = prereposetups or []
84 self.prereposetups = prereposetups or []
85
85
86 # store the parsed and canonical command
86 # store the parsed and canonical command
87 self.canonical_command = None
87 self.canonical_command = None
88
88
89 def _runexithandlers(self):
89 def _runexithandlers(self):
90 exc = None
90 exc = None
91 handlers = self.ui._exithandlers
91 handlers = self.ui._exithandlers
92 try:
92 try:
93 while handlers:
93 while handlers:
94 func, args, kwargs = handlers.pop()
94 func, args, kwargs = handlers.pop()
95 try:
95 try:
96 func(*args, **kwargs)
96 func(*args, **kwargs)
97 except: # re-raises below
97 except: # re-raises below
98 if exc is None:
98 if exc is None:
99 exc = sys.exc_info()[1]
99 exc = sys.exc_info()[1]
100 self.ui.warnnoi18n(b'error in exit handlers:\n')
100 self.ui.warnnoi18n(b'error in exit handlers:\n')
101 self.ui.traceback(force=True)
101 self.ui.traceback(force=True)
102 finally:
102 finally:
103 if exc is not None:
103 if exc is not None:
104 raise exc
104 raise exc
105
105
106
106
107 def run():
107 def run():
108 """run the command in sys.argv"""
108 """run the command in sys.argv"""
109 try:
109 try:
110 initstdio()
110 initstdio()
111 with tracing.log('parse args into request'):
111 with tracing.log('parse args into request'):
112 req = request(pycompat.sysargv[1:])
112 req = request(pycompat.sysargv[1:])
113 err = None
113 err = None
114 try:
114 try:
115 status = dispatch(req)
115 status = dispatch(req)
116 except error.StdioError as e:
116 except error.StdioError as e:
117 err = e
117 err = e
118 status = -1
118 status = -1
119
119
120 # In all cases we try to flush stdio streams.
120 # In all cases we try to flush stdio streams.
121 if util.safehasattr(req.ui, b'fout'):
121 if util.safehasattr(req.ui, b'fout'):
122 assert req.ui is not None # help pytype
122 assert req.ui is not None # help pytype
123 assert req.ui.fout is not None # help pytype
123 assert req.ui.fout is not None # help pytype
124 try:
124 try:
125 req.ui.fout.flush()
125 req.ui.fout.flush()
126 except IOError as e:
126 except IOError as e:
127 err = e
127 err = e
128 status = -1
128 status = -1
129
129
130 if util.safehasattr(req.ui, b'ferr'):
130 if util.safehasattr(req.ui, b'ferr'):
131 assert req.ui is not None # help pytype
131 assert req.ui is not None # help pytype
132 assert req.ui.ferr is not None # help pytype
132 assert req.ui.ferr is not None # help pytype
133 try:
133 try:
134 if err is not None and err.errno != errno.EPIPE:
134 if err is not None and err.errno != errno.EPIPE:
135 req.ui.ferr.write(
135 req.ui.ferr.write(
136 b'abort: %s\n' % encoding.strtolocal(err.strerror)
136 b'abort: %s\n' % encoding.strtolocal(err.strerror)
137 )
137 )
138 req.ui.ferr.flush()
138 req.ui.ferr.flush()
139 # There's not much we can do about an I/O error here. So (possibly)
139 # There's not much we can do about an I/O error here. So (possibly)
140 # change the status code and move on.
140 # change the status code and move on.
141 except IOError:
141 except IOError:
142 status = -1
142 status = -1
143
143
144 _silencestdio()
144 _silencestdio()
145 except KeyboardInterrupt:
145 except KeyboardInterrupt:
146 # Catch early/late KeyboardInterrupt as last ditch. Here nothing will
146 # Catch early/late KeyboardInterrupt as last ditch. Here nothing will
147 # be printed to console to avoid another IOError/KeyboardInterrupt.
147 # be printed to console to avoid another IOError/KeyboardInterrupt.
148 status = -1
148 status = -1
149 sys.exit(status & 255)
149 sys.exit(status & 255)
150
150
151
151
152 if pycompat.ispy3:
152 if pycompat.ispy3:
153
153
154 def initstdio():
154 def initstdio():
155 # stdio streams on Python 3 are io.TextIOWrapper instances proxying another
155 # stdio streams on Python 3 are io.TextIOWrapper instances proxying another
156 # buffer. These streams will normalize \n to \r\n by default. Mercurial's
156 # buffer. These streams will normalize \n to \r\n by default. Mercurial's
157 # preferred mechanism for writing output (ui.write()) uses io.BufferedWriter
157 # preferred mechanism for writing output (ui.write()) uses io.BufferedWriter
158 # instances, which write to the underlying stdio file descriptor in binary
158 # instances, which write to the underlying stdio file descriptor in binary
159 # mode. ui.write() uses \n for line endings and no line ending normalization
159 # mode. ui.write() uses \n for line endings and no line ending normalization
160 # is attempted through this interface. This "just works," even if the system
160 # is attempted through this interface. This "just works," even if the system
161 # preferred line ending is not \n.
161 # preferred line ending is not \n.
162 #
162 #
163 # But some parts of Mercurial (e.g. hooks) can still send data to sys.stdout
163 # But some parts of Mercurial (e.g. hooks) can still send data to sys.stdout
164 # and sys.stderr. They will inherit the line ending normalization settings,
164 # and sys.stderr. They will inherit the line ending normalization settings,
165 # potentially causing e.g. \r\n to be emitted. Since emitting \n should
165 # potentially causing e.g. \r\n to be emitted. Since emitting \n should
166 # "just work," here we change the sys.* streams to disable line ending
166 # "just work," here we change the sys.* streams to disable line ending
167 # normalization, ensuring compatibility with our ui type.
167 # normalization, ensuring compatibility with our ui type.
168
168
169 # write_through is new in Python 3.7.
169 # write_through is new in Python 3.7.
170 kwargs = {
170 kwargs = {
171 "newline": "\n",
171 "newline": "\n",
172 "line_buffering": sys.stdout.line_buffering,
172 "line_buffering": sys.stdout.line_buffering,
173 }
173 }
174 if util.safehasattr(sys.stdout, "write_through"):
174 if util.safehasattr(sys.stdout, "write_through"):
175 kwargs["write_through"] = sys.stdout.write_through
175 kwargs["write_through"] = sys.stdout.write_through
176 sys.stdout = io.TextIOWrapper(
176 sys.stdout = io.TextIOWrapper(
177 sys.stdout.buffer, sys.stdout.encoding, sys.stdout.errors, **kwargs
177 sys.stdout.buffer, sys.stdout.encoding, sys.stdout.errors, **kwargs
178 )
178 )
179
179
180 kwargs = {
180 kwargs = {
181 "newline": "\n",
181 "newline": "\n",
182 "line_buffering": sys.stderr.line_buffering,
182 "line_buffering": sys.stderr.line_buffering,
183 }
183 }
184 if util.safehasattr(sys.stderr, "write_through"):
184 if util.safehasattr(sys.stderr, "write_through"):
185 kwargs["write_through"] = sys.stderr.write_through
185 kwargs["write_through"] = sys.stderr.write_through
186 sys.stderr = io.TextIOWrapper(
186 sys.stderr = io.TextIOWrapper(
187 sys.stderr.buffer, sys.stderr.encoding, sys.stderr.errors, **kwargs
187 sys.stderr.buffer, sys.stderr.encoding, sys.stderr.errors, **kwargs
188 )
188 )
189
189
190 # No write_through on read-only stream.
190 # No write_through on read-only stream.
191 sys.stdin = io.TextIOWrapper(
191 sys.stdin = io.TextIOWrapper(
192 sys.stdin.buffer,
192 sys.stdin.buffer,
193 sys.stdin.encoding,
193 sys.stdin.encoding,
194 sys.stdin.errors,
194 sys.stdin.errors,
195 # None is universal newlines mode.
195 # None is universal newlines mode.
196 newline=None,
196 newline=None,
197 line_buffering=sys.stdin.line_buffering,
197 line_buffering=sys.stdin.line_buffering,
198 )
198 )
199
199
200 def _silencestdio():
200 def _silencestdio():
201 for fp in (sys.stdout, sys.stderr):
201 for fp in (sys.stdout, sys.stderr):
202 # Check if the file is okay
202 # Check if the file is okay
203 try:
203 try:
204 fp.flush()
204 fp.flush()
205 continue
205 continue
206 except IOError:
206 except IOError:
207 pass
207 pass
208 # Otherwise mark it as closed to silence "Exception ignored in"
208 # Otherwise mark it as closed to silence "Exception ignored in"
209 # message emitted by the interpreter finalizer. Be careful to
209 # message emitted by the interpreter finalizer. Be careful to
210 # not close procutil.stdout, which may be a fdopen-ed file object
210 # not close procutil.stdout, which may be a fdopen-ed file object
211 # and its close() actually closes the underlying file descriptor.
211 # and its close() actually closes the underlying file descriptor.
212 try:
212 try:
213 fp.close()
213 fp.close()
214 except IOError:
214 except IOError:
215 pass
215 pass
216
216
217
217
218 else:
218 else:
219
219
220 def initstdio():
220 def initstdio():
221 for fp in (sys.stdin, sys.stdout, sys.stderr):
221 for fp in (sys.stdin, sys.stdout, sys.stderr):
222 procutil.setbinary(fp)
222 procutil.setbinary(fp)
223
223
224 def _silencestdio():
224 def _silencestdio():
225 pass
225 pass
226
226
227
227
228 def _formatargs(args):
228 def _formatargs(args):
229 return b' '.join(procutil.shellquote(a) for a in args)
229 return b' '.join(procutil.shellquote(a) for a in args)
230
230
231
231
232 def dispatch(req):
232 def dispatch(req):
233 """run the command specified in req.args; returns an integer status code"""
233 """run the command specified in req.args; returns an integer status code"""
234 with tracing.log('dispatch.dispatch'):
234 with tracing.log('dispatch.dispatch'):
235 if req.ferr:
235 if req.ferr:
236 ferr = req.ferr
236 ferr = req.ferr
237 elif req.ui:
237 elif req.ui:
238 ferr = req.ui.ferr
238 ferr = req.ui.ferr
239 else:
239 else:
240 ferr = procutil.stderr
240 ferr = procutil.stderr
241
241
242 try:
242 try:
243 if not req.ui:
243 if not req.ui:
244 req.ui = uimod.ui.load()
244 req.ui = uimod.ui.load()
245 req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
245 req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
246 if req.earlyoptions[b'traceback']:
246 if req.earlyoptions[b'traceback']:
247 req.ui.setconfig(b'ui', b'traceback', b'on', b'--traceback')
247 req.ui.setconfig(b'ui', b'traceback', b'on', b'--traceback')
248
248
249 # set ui streams from the request
249 # set ui streams from the request
250 if req.fin:
250 if req.fin:
251 req.ui.fin = req.fin
251 req.ui.fin = req.fin
252 if req.fout:
252 if req.fout:
253 req.ui.fout = req.fout
253 req.ui.fout = req.fout
254 if req.ferr:
254 if req.ferr:
255 req.ui.ferr = req.ferr
255 req.ui.ferr = req.ferr
256 if req.fmsg:
256 if req.fmsg:
257 req.ui.fmsg = req.fmsg
257 req.ui.fmsg = req.fmsg
258 except error.Abort as inst:
258 except error.Abort as inst:
259 ferr.write(inst.format())
259 ferr.write(inst.format())
260 return -1
260 return -1
261
261
262 msg = _formatargs(req.args)
262 msg = _formatargs(req.args)
263 starttime = util.timer()
263 starttime = util.timer()
264 ret = 1 # default of Python exit code on unhandled exception
264 ret = 1 # default of Python exit code on unhandled exception
265 try:
265 try:
266 ret = _runcatch(req) or 0
266 ret = _runcatch(req) or 0
267 except error.ProgrammingError as inst:
267 except error.ProgrammingError as inst:
268 req.ui.error(_(b'** ProgrammingError: %s\n') % inst)
268 req.ui.error(_(b'** ProgrammingError: %s\n') % inst)
269 if inst.hint:
269 if inst.hint:
270 req.ui.error(_(b'** (%s)\n') % inst.hint)
270 req.ui.error(_(b'** (%s)\n') % inst.hint)
271 raise
271 raise
272 except KeyboardInterrupt as inst:
272 except KeyboardInterrupt as inst:
273 try:
273 try:
274 if isinstance(inst, error.SignalInterrupt):
274 if isinstance(inst, error.SignalInterrupt):
275 msg = _(b"killed!\n")
275 msg = _(b"killed!\n")
276 else:
276 else:
277 msg = _(b"interrupted!\n")
277 msg = _(b"interrupted!\n")
278 req.ui.error(msg)
278 req.ui.error(msg)
279 except error.SignalInterrupt:
279 except error.SignalInterrupt:
280 # maybe pager would quit without consuming all the output, and
280 # maybe pager would quit without consuming all the output, and
281 # SIGPIPE was raised. we cannot print anything in this case.
281 # SIGPIPE was raised. we cannot print anything in this case.
282 pass
282 pass
283 except IOError as inst:
283 except IOError as inst:
284 if inst.errno != errno.EPIPE:
284 if inst.errno != errno.EPIPE:
285 raise
285 raise
286 ret = -1
286 ret = -1
287 finally:
287 finally:
288 duration = util.timer() - starttime
288 duration = util.timer() - starttime
289 req.ui.flush() # record blocked times
289 req.ui.flush() # record blocked times
290 if req.ui.logblockedtimes:
290 if req.ui.logblockedtimes:
291 req.ui._blockedtimes[b'command_duration'] = duration * 1000
291 req.ui._blockedtimes[b'command_duration'] = duration * 1000
292 req.ui.log(
292 req.ui.log(
293 b'uiblocked',
293 b'uiblocked',
294 b'ui blocked ms\n',
294 b'ui blocked ms\n',
295 **pycompat.strkwargs(req.ui._blockedtimes)
295 **pycompat.strkwargs(req.ui._blockedtimes)
296 )
296 )
297 return_code = ret & 255
297 return_code = ret & 255
298 req.ui.log(
298 req.ui.log(
299 b"commandfinish",
299 b"commandfinish",
300 b"%s exited %d after %0.2f seconds\n",
300 b"%s exited %d after %0.2f seconds\n",
301 msg,
301 msg,
302 return_code,
302 return_code,
303 duration,
303 duration,
304 return_code=return_code,
304 return_code=return_code,
305 duration=duration,
305 duration=duration,
306 canonical_command=req.canonical_command,
306 canonical_command=req.canonical_command,
307 )
307 )
308 try:
308 try:
309 req._runexithandlers()
309 req._runexithandlers()
310 except: # exiting, so no re-raises
310 except: # exiting, so no re-raises
311 ret = ret or -1
311 ret = ret or -1
312 # do flush again since ui.log() and exit handlers may write to ui
312 # do flush again since ui.log() and exit handlers may write to ui
313 req.ui.flush()
313 req.ui.flush()
314 return ret
314 return ret
315
315
316
316
317 def _runcatch(req):
317 def _runcatch(req):
318 with tracing.log('dispatch._runcatch'):
318 with tracing.log('dispatch._runcatch'):
319
319
320 def catchterm(*args):
320 def catchterm(*args):
321 raise error.SignalInterrupt
321 raise error.SignalInterrupt
322
322
323 ui = req.ui
323 ui = req.ui
324 try:
324 try:
325 for name in b'SIGBREAK', b'SIGHUP', b'SIGTERM':
325 for name in b'SIGBREAK', b'SIGHUP', b'SIGTERM':
326 num = getattr(signal, name, None)
326 num = getattr(signal, name, None)
327 if num:
327 if num:
328 signal.signal(num, catchterm)
328 signal.signal(num, catchterm)
329 except ValueError:
329 except ValueError:
330 pass # happens if called in a thread
330 pass # happens if called in a thread
331
331
332 def _runcatchfunc():
332 def _runcatchfunc():
333 realcmd = None
333 realcmd = None
334 try:
334 try:
335 cmdargs = fancyopts.fancyopts(
335 cmdargs = fancyopts.fancyopts(
336 req.args[:], commands.globalopts, {}
336 req.args[:], commands.globalopts, {}
337 )
337 )
338 cmd = cmdargs[0]
338 cmd = cmdargs[0]
339 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
339 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
340 realcmd = aliases[0]
340 realcmd = aliases[0]
341 except (
341 except (
342 error.UnknownCommand,
342 error.UnknownCommand,
343 error.AmbiguousCommand,
343 error.AmbiguousCommand,
344 IndexError,
344 IndexError,
345 getopt.GetoptError,
345 getopt.GetoptError,
346 ):
346 ):
347 # Don't handle this here. We know the command is
347 # Don't handle this here. We know the command is
348 # invalid, but all we're worried about for now is that
348 # invalid, but all we're worried about for now is that
349 # it's not a command that server operators expect to
349 # it's not a command that server operators expect to
350 # be safe to offer to users in a sandbox.
350 # be safe to offer to users in a sandbox.
351 pass
351 pass
352 if realcmd == b'serve' and b'--stdio' in cmdargs:
352 if realcmd == b'serve' and b'--stdio' in cmdargs:
353 # We want to constrain 'hg serve --stdio' instances pretty
353 # We want to constrain 'hg serve --stdio' instances pretty
354 # closely, as many shared-ssh access tools want to grant
354 # closely, as many shared-ssh access tools want to grant
355 # access to run *only* 'hg -R $repo serve --stdio'. We
355 # access to run *only* 'hg -R $repo serve --stdio'. We
356 # restrict to exactly that set of arguments, and prohibit
356 # restrict to exactly that set of arguments, and prohibit
357 # any repo name that starts with '--' to prevent
357 # any repo name that starts with '--' to prevent
358 # shenanigans wherein a user does something like pass
358 # shenanigans wherein a user does something like pass
359 # --debugger or --config=ui.debugger=1 as a repo
359 # --debugger or --config=ui.debugger=1 as a repo
360 # name. This used to actually run the debugger.
360 # name. This used to actually run the debugger.
361 if (
361 if (
362 len(req.args) != 4
362 len(req.args) != 4
363 or req.args[0] != b'-R'
363 or req.args[0] != b'-R'
364 or req.args[1].startswith(b'--')
364 or req.args[1].startswith(b'--')
365 or req.args[2] != b'serve'
365 or req.args[2] != b'serve'
366 or req.args[3] != b'--stdio'
366 or req.args[3] != b'--stdio'
367 ):
367 ):
368 raise error.Abort(
368 raise error.Abort(
369 _(b'potentially unsafe serve --stdio invocation: %s')
369 _(b'potentially unsafe serve --stdio invocation: %s')
370 % (stringutil.pprint(req.args),)
370 % (stringutil.pprint(req.args),)
371 )
371 )
372
372
373 try:
373 try:
374 debugger = b'pdb'
374 debugger = b'pdb'
375 debugtrace = {b'pdb': pdb.set_trace}
375 debugtrace = {b'pdb': pdb.set_trace}
376 debugmortem = {b'pdb': pdb.post_mortem}
376 debugmortem = {b'pdb': pdb.post_mortem}
377
377
378 # read --config before doing anything else
378 # read --config before doing anything else
379 # (e.g. to change trust settings for reading .hg/hgrc)
379 # (e.g. to change trust settings for reading .hg/hgrc)
380 cfgs = _parseconfig(req.ui, req.earlyoptions[b'config'])
380 cfgs = _parseconfig(req.ui, req.earlyoptions[b'config'])
381
381
382 if req.repo:
382 if req.repo:
383 # copy configs that were passed on the cmdline (--config) to
383 # copy configs that were passed on the cmdline (--config) to
384 # the repo ui
384 # the repo ui
385 for sec, name, val in cfgs:
385 for sec, name, val in cfgs:
386 req.repo.ui.setconfig(
386 req.repo.ui.setconfig(
387 sec, name, val, source=b'--config'
387 sec, name, val, source=b'--config'
388 )
388 )
389
389
390 # developer config: ui.debugger
390 # developer config: ui.debugger
391 debugger = ui.config(b"ui", b"debugger")
391 debugger = ui.config(b"ui", b"debugger")
392 debugmod = pdb
392 debugmod = pdb
393 if not debugger or ui.plain():
393 if not debugger or ui.plain():
394 # if we are in HGPLAIN mode, then disable custom debugging
394 # if we are in HGPLAIN mode, then disable custom debugging
395 debugger = b'pdb'
395 debugger = b'pdb'
396 elif req.earlyoptions[b'debugger']:
396 elif req.earlyoptions[b'debugger']:
397 # This import can be slow for fancy debuggers, so only
397 # This import can be slow for fancy debuggers, so only
398 # do it when absolutely necessary, i.e. when actual
398 # do it when absolutely necessary, i.e. when actual
399 # debugging has been requested
399 # debugging has been requested
400 with demandimport.deactivated():
400 with demandimport.deactivated():
401 try:
401 try:
402 debugmod = __import__(debugger)
402 debugmod = __import__(debugger)
403 except ImportError:
403 except ImportError:
404 pass # Leave debugmod = pdb
404 pass # Leave debugmod = pdb
405
405
406 debugtrace[debugger] = debugmod.set_trace
406 debugtrace[debugger] = debugmod.set_trace
407 debugmortem[debugger] = debugmod.post_mortem
407 debugmortem[debugger] = debugmod.post_mortem
408
408
409 # enter the debugger before command execution
409 # enter the debugger before command execution
410 if req.earlyoptions[b'debugger']:
410 if req.earlyoptions[b'debugger']:
411 ui.warn(
411 ui.warn(
412 _(
412 _(
413 b"entering debugger - "
413 b"entering debugger - "
414 b"type c to continue starting hg or h for help\n"
414 b"type c to continue starting hg or h for help\n"
415 )
415 )
416 )
416 )
417
417
418 if (
418 if (
419 debugger != b'pdb'
419 debugger != b'pdb'
420 and debugtrace[debugger] == debugtrace[b'pdb']
420 and debugtrace[debugger] == debugtrace[b'pdb']
421 ):
421 ):
422 ui.warn(
422 ui.warn(
423 _(
423 _(
424 b"%s debugger specified "
424 b"%s debugger specified "
425 b"but its module was not found\n"
425 b"but its module was not found\n"
426 )
426 )
427 % debugger
427 % debugger
428 )
428 )
429 with demandimport.deactivated():
429 with demandimport.deactivated():
430 debugtrace[debugger]()
430 debugtrace[debugger]()
431 try:
431 try:
432 return _dispatch(req)
432 return _dispatch(req)
433 finally:
433 finally:
434 ui.flush()
434 ui.flush()
435 except: # re-raises
435 except: # re-raises
436 # enter the debugger when we hit an exception
436 # enter the debugger when we hit an exception
437 if req.earlyoptions[b'debugger']:
437 if req.earlyoptions[b'debugger']:
438 traceback.print_exc()
438 traceback.print_exc()
439 debugmortem[debugger](sys.exc_info()[2])
439 debugmortem[debugger](sys.exc_info()[2])
440 raise
440 raise
441
441
442 return _callcatch(ui, _runcatchfunc)
442 return _callcatch(ui, _runcatchfunc)
443
443
444
444
445 def _callcatch(ui, func):
445 def _callcatch(ui, func):
446 """like scmutil.callcatch but handles more high-level exceptions about
446 """like scmutil.callcatch but handles more high-level exceptions about
447 config parsing and commands. besides, use handlecommandexception to handle
447 config parsing and commands. besides, use handlecommandexception to handle
448 uncaught exceptions.
448 uncaught exceptions.
449 """
449 """
450 try:
450 try:
451 return scmutil.callcatch(ui, func)
451 return scmutil.callcatch(ui, func)
452 except error.AmbiguousCommand as inst:
452 except error.AmbiguousCommand as inst:
453 ui.warn(
453 ui.warn(
454 _(b"hg: command '%s' is ambiguous:\n %s\n")
454 _(b"hg: command '%s' is ambiguous:\n %s\n")
455 % (inst.prefix, b" ".join(inst.matches))
455 % (inst.prefix, b" ".join(inst.matches))
456 )
456 )
457 except error.CommandError as inst:
457 except error.CommandError as inst:
458 if inst.command:
458 if inst.command:
459 ui.pager(b'help')
459 ui.pager(b'help')
460 msgbytes = pycompat.bytestr(inst.message)
460 msgbytes = pycompat.bytestr(inst.message)
461 ui.warn(_(b"hg %s: %s\n") % (inst.command, msgbytes))
461 ui.warn(_(b"hg %s: %s\n") % (inst.command, msgbytes))
462 commands.help_(ui, inst.command, full=False, command=True)
462 commands.help_(ui, inst.command, full=False, command=True)
463 else:
463 else:
464 ui.warn(_(b"hg: %s\n") % inst.message)
464 ui.warn(_(b"hg: %s\n") % inst.message)
465 ui.warn(_(b"(use 'hg help -v' for a list of global options)\n"))
465 ui.warn(_(b"(use 'hg help -v' for a list of global options)\n"))
466 except error.UnknownCommand as inst:
466 except error.UnknownCommand as inst:
467 nocmdmsg = _(b"hg: unknown command '%s'\n") % inst.command
467 nocmdmsg = _(b"hg: unknown command '%s'\n") % inst.command
468 try:
468 try:
469 # check if the command is in a disabled extension
469 # check if the command is in a disabled extension
470 # (but don't check for extensions themselves)
470 # (but don't check for extensions themselves)
471 formatted = help.formattedhelp(
471 formatted = help.formattedhelp(
472 ui, commands, inst.command, unknowncmd=True
472 ui, commands, inst.command, unknowncmd=True
473 )
473 )
474 ui.warn(nocmdmsg)
474 ui.warn(nocmdmsg)
475 ui.write(formatted)
475 ui.write(formatted)
476 except (error.UnknownCommand, error.Abort):
476 except (error.UnknownCommand, error.Abort):
477 suggested = False
477 suggested = False
478 if inst.all_commands:
478 if inst.all_commands:
479 sim = error.getsimilar(inst.all_commands, inst.command)
479 sim = error.getsimilar(inst.all_commands, inst.command)
480 if sim:
480 if sim:
481 ui.warn(nocmdmsg)
481 ui.warn(nocmdmsg)
482 ui.warn(b"(%s)\n" % error.similarity_hint(sim))
482 ui.warn(b"(%s)\n" % error.similarity_hint(sim))
483 suggested = True
483 suggested = True
484 if not suggested:
484 if not suggested:
485 ui.warn(nocmdmsg)
485 ui.warn(nocmdmsg)
486 ui.warn(_(b"(use 'hg help' for a list of commands)\n"))
486 ui.warn(_(b"(use 'hg help' for a list of commands)\n"))
487 except IOError:
487 except IOError:
488 raise
488 raise
489 except KeyboardInterrupt:
489 except KeyboardInterrupt:
490 raise
490 raise
491 except: # probably re-raises
491 except: # probably re-raises
492 if not handlecommandexception(ui):
492 if not handlecommandexception(ui):
493 raise
493 raise
494
494
495 return -1
495 return -1
496
496
497
497
498 def aliasargs(fn, givenargs):
498 def aliasargs(fn, givenargs):
499 args = []
499 args = []
500 # only care about alias 'args', ignore 'args' set by extensions.wrapfunction
500 # only care about alias 'args', ignore 'args' set by extensions.wrapfunction
501 if not util.safehasattr(fn, b'_origfunc'):
501 if not util.safehasattr(fn, b'_origfunc'):
502 args = getattr(fn, 'args', args)
502 args = getattr(fn, 'args', args)
503 if args:
503 if args:
504 cmd = b' '.join(map(procutil.shellquote, args))
504 cmd = b' '.join(map(procutil.shellquote, args))
505
505
506 nums = []
506 nums = []
507
507
508 def replacer(m):
508 def replacer(m):
509 num = int(m.group(1)) - 1
509 num = int(m.group(1)) - 1
510 nums.append(num)
510 nums.append(num)
511 if num < len(givenargs):
511 if num < len(givenargs):
512 return givenargs[num]
512 return givenargs[num]
513 raise error.InputError(_(b'too few arguments for command alias'))
513 raise error.InputError(_(b'too few arguments for command alias'))
514
514
515 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd)
515 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd)
516 givenargs = [x for i, x in enumerate(givenargs) if i not in nums]
516 givenargs = [x for i, x in enumerate(givenargs) if i not in nums]
517 args = pycompat.shlexsplit(cmd)
517 args = pycompat.shlexsplit(cmd)
518 return args + givenargs
518 return args + givenargs
519
519
520
520
521 def aliasinterpolate(name, args, cmd):
521 def aliasinterpolate(name, args, cmd):
522 """interpolate args into cmd for shell aliases
522 """interpolate args into cmd for shell aliases
523
523
524 This also handles $0, $@ and "$@".
524 This also handles $0, $@ and "$@".
525 """
525 """
526 # util.interpolate can't deal with "$@" (with quotes) because it's only
526 # util.interpolate can't deal with "$@" (with quotes) because it's only
527 # built to match prefix + patterns.
527 # built to match prefix + patterns.
528 replacemap = {b'$%d' % (i + 1): arg for i, arg in enumerate(args)}
528 replacemap = {b'$%d' % (i + 1): arg for i, arg in enumerate(args)}
529 replacemap[b'$0'] = name
529 replacemap[b'$0'] = name
530 replacemap[b'$$'] = b'$'
530 replacemap[b'$$'] = b'$'
531 replacemap[b'$@'] = b' '.join(args)
531 replacemap[b'$@'] = b' '.join(args)
532 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
532 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
533 # parameters, separated out into words. Emulate the same behavior here by
533 # parameters, separated out into words. Emulate the same behavior here by
534 # quoting the arguments individually. POSIX shells will then typically
534 # quoting the arguments individually. POSIX shells will then typically
535 # tokenize each argument into exactly one word.
535 # tokenize each argument into exactly one word.
536 replacemap[b'"$@"'] = b' '.join(procutil.shellquote(arg) for arg in args)
536 replacemap[b'"$@"'] = b' '.join(procutil.shellquote(arg) for arg in args)
537 # escape '\$' for regex
537 # escape '\$' for regex
538 regex = b'|'.join(replacemap.keys()).replace(b'$', br'\$')
538 regex = b'|'.join(replacemap.keys()).replace(b'$', br'\$')
539 r = re.compile(regex)
539 r = re.compile(regex)
540 return r.sub(lambda x: replacemap[x.group()], cmd)
540 return r.sub(lambda x: replacemap[x.group()], cmd)
541
541
542
542
543 class cmdalias(object):
543 class cmdalias(object):
544 def __init__(self, ui, name, definition, cmdtable, source):
544 def __init__(self, ui, name, definition, cmdtable, source):
545 self.name = self.cmd = name
545 self.name = self.cmd = name
546 self.cmdname = b''
546 self.cmdname = b''
547 self.definition = definition
547 self.definition = definition
548 self.fn = None
548 self.fn = None
549 self.givenargs = []
549 self.givenargs = []
550 self.opts = []
550 self.opts = []
551 self.help = b''
551 self.help = b''
552 self.badalias = None
552 self.badalias = None
553 self.unknowncmd = False
553 self.unknowncmd = False
554 self.source = source
554 self.source = source
555
555
556 try:
556 try:
557 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
557 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
558 for alias, e in pycompat.iteritems(cmdtable):
558 for alias, e in pycompat.iteritems(cmdtable):
559 if e is entry:
559 if e is entry:
560 self.cmd = alias
560 self.cmd = alias
561 break
561 break
562 self.shadows = True
562 self.shadows = True
563 except error.UnknownCommand:
563 except error.UnknownCommand:
564 self.shadows = False
564 self.shadows = False
565
565
566 if not self.definition:
566 if not self.definition:
567 self.badalias = _(b"no definition for alias '%s'") % self.name
567 self.badalias = _(b"no definition for alias '%s'") % self.name
568 return
568 return
569
569
570 if self.definition.startswith(b'!'):
570 if self.definition.startswith(b'!'):
571 shdef = self.definition[1:]
571 shdef = self.definition[1:]
572 self.shell = True
572 self.shell = True
573
573
574 def fn(ui, *args):
574 def fn(ui, *args):
575 env = {b'HG_ARGS': b' '.join((self.name,) + args)}
575 env = {b'HG_ARGS': b' '.join((self.name,) + args)}
576
576
577 def _checkvar(m):
577 def _checkvar(m):
578 if m.groups()[0] == b'$':
578 if m.groups()[0] == b'$':
579 return m.group()
579 return m.group()
580 elif int(m.groups()[0]) <= len(args):
580 elif int(m.groups()[0]) <= len(args):
581 return m.group()
581 return m.group()
582 else:
582 else:
583 ui.debug(
583 ui.debug(
584 b"No argument found for substitution "
584 b"No argument found for substitution "
585 b"of %i variable in alias '%s' definition.\n"
585 b"of %i variable in alias '%s' definition.\n"
586 % (int(m.groups()[0]), self.name)
586 % (int(m.groups()[0]), self.name)
587 )
587 )
588 return b''
588 return b''
589
589
590 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef)
590 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef)
591 cmd = aliasinterpolate(self.name, args, cmd)
591 cmd = aliasinterpolate(self.name, args, cmd)
592 return ui.system(
592 return ui.system(
593 cmd, environ=env, blockedtag=b'alias_%s' % self.name
593 cmd, environ=env, blockedtag=b'alias_%s' % self.name
594 )
594 )
595
595
596 self.fn = fn
596 self.fn = fn
597 self.alias = True
597 self.alias = True
598 self._populatehelp(ui, name, shdef, self.fn)
598 self._populatehelp(ui, name, shdef, self.fn)
599 return
599 return
600
600
601 try:
601 try:
602 args = pycompat.shlexsplit(self.definition)
602 args = pycompat.shlexsplit(self.definition)
603 except ValueError as inst:
603 except ValueError as inst:
604 self.badalias = _(b"error in definition for alias '%s': %s") % (
604 self.badalias = _(b"error in definition for alias '%s': %s") % (
605 self.name,
605 self.name,
606 stringutil.forcebytestr(inst),
606 stringutil.forcebytestr(inst),
607 )
607 )
608 return
608 return
609 earlyopts, args = _earlysplitopts(args)
609 earlyopts, args = _earlysplitopts(args)
610 if earlyopts:
610 if earlyopts:
611 self.badalias = _(
611 self.badalias = _(
612 b"error in definition for alias '%s': %s may "
612 b"error in definition for alias '%s': %s may "
613 b"only be given on the command line"
613 b"only be given on the command line"
614 ) % (self.name, b'/'.join(pycompat.ziplist(*earlyopts)[0]))
614 ) % (self.name, b'/'.join(pycompat.ziplist(*earlyopts)[0]))
615 return
615 return
616 self.cmdname = cmd = args.pop(0)
616 self.cmdname = cmd = args.pop(0)
617 self.givenargs = args
617 self.givenargs = args
618
618
619 try:
619 try:
620 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
620 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
621 if len(tableentry) > 2:
621 if len(tableentry) > 2:
622 self.fn, self.opts, cmdhelp = tableentry
622 self.fn, self.opts, cmdhelp = tableentry
623 else:
623 else:
624 self.fn, self.opts = tableentry
624 self.fn, self.opts = tableentry
625 cmdhelp = None
625 cmdhelp = None
626
626
627 self.alias = True
627 self.alias = True
628 self._populatehelp(ui, name, cmd, self.fn, cmdhelp)
628 self._populatehelp(ui, name, cmd, self.fn, cmdhelp)
629
629
630 except error.UnknownCommand:
630 except error.UnknownCommand:
631 self.badalias = _(
631 self.badalias = _(
632 b"alias '%s' resolves to unknown command '%s'"
632 b"alias '%s' resolves to unknown command '%s'"
633 ) % (
633 ) % (
634 self.name,
634 self.name,
635 cmd,
635 cmd,
636 )
636 )
637 self.unknowncmd = True
637 self.unknowncmd = True
638 except error.AmbiguousCommand:
638 except error.AmbiguousCommand:
639 self.badalias = _(
639 self.badalias = _(
640 b"alias '%s' resolves to ambiguous command '%s'"
640 b"alias '%s' resolves to ambiguous command '%s'"
641 ) % (
641 ) % (
642 self.name,
642 self.name,
643 cmd,
643 cmd,
644 )
644 )
645
645
646 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
646 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
647 # confine strings to be passed to i18n.gettext()
647 # confine strings to be passed to i18n.gettext()
648 cfg = {}
648 cfg = {}
649 for k in (b'doc', b'help', b'category'):
649 for k in (b'doc', b'help', b'category'):
650 v = ui.config(b'alias', b'%s:%s' % (name, k), None)
650 v = ui.config(b'alias', b'%s:%s' % (name, k), None)
651 if v is None:
651 if v is None:
652 continue
652 continue
653 if not encoding.isasciistr(v):
653 if not encoding.isasciistr(v):
654 self.badalias = _(
654 self.badalias = _(
655 b"non-ASCII character in alias definition '%s:%s'"
655 b"non-ASCII character in alias definition '%s:%s'"
656 ) % (name, k)
656 ) % (name, k)
657 return
657 return
658 cfg[k] = v
658 cfg[k] = v
659
659
660 self.help = cfg.get(b'help', defaulthelp or b'')
660 self.help = cfg.get(b'help', defaulthelp or b'')
661 if self.help and self.help.startswith(b"hg " + cmd):
661 if self.help and self.help.startswith(b"hg " + cmd):
662 # drop prefix in old-style help lines so hg shows the alias
662 # drop prefix in old-style help lines so hg shows the alias
663 self.help = self.help[4 + len(cmd) :]
663 self.help = self.help[4 + len(cmd) :]
664
664
665 self.owndoc = b'doc' in cfg
665 self.owndoc = b'doc' in cfg
666 doc = cfg.get(b'doc', pycompat.getdoc(fn))
666 doc = cfg.get(b'doc', pycompat.getdoc(fn))
667 if doc is not None:
667 if doc is not None:
668 doc = pycompat.sysstr(doc)
668 doc = pycompat.sysstr(doc)
669 self.__doc__ = doc
669 self.__doc__ = doc
670
670
671 self.helpcategory = cfg.get(
671 self.helpcategory = cfg.get(
672 b'category', registrar.command.CATEGORY_NONE
672 b'category', registrar.command.CATEGORY_NONE
673 )
673 )
674
674
675 @property
675 @property
676 def args(self):
676 def args(self):
677 args = pycompat.maplist(util.expandpath, self.givenargs)
677 args = pycompat.maplist(util.expandpath, self.givenargs)
678 return aliasargs(self.fn, args)
678 return aliasargs(self.fn, args)
679
679
680 def __getattr__(self, name):
680 def __getattr__(self, name):
681 adefaults = {
681 adefaults = {
682 'norepo': True,
682 'norepo': True,
683 'intents': set(),
683 'intents': set(),
684 'optionalrepo': False,
684 'optionalrepo': False,
685 'inferrepo': False,
685 'inferrepo': False,
686 }
686 }
687 if name not in adefaults:
687 if name not in adefaults:
688 raise AttributeError(name)
688 raise AttributeError(name)
689 if self.badalias or util.safehasattr(self, b'shell'):
689 if self.badalias or util.safehasattr(self, b'shell'):
690 return adefaults[name]
690 return adefaults[name]
691 return getattr(self.fn, name)
691 return getattr(self.fn, name)
692
692
693 def __call__(self, ui, *args, **opts):
693 def __call__(self, ui, *args, **opts):
694 if self.badalias:
694 if self.badalias:
695 hint = None
695 hint = None
696 if self.unknowncmd:
696 if self.unknowncmd:
697 try:
697 try:
698 # check if the command is in a disabled extension
698 # check if the command is in a disabled extension
699 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
699 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
700 hint = _(b"'%s' is provided by '%s' extension") % (cmd, ext)
700 hint = _(b"'%s' is provided by '%s' extension") % (cmd, ext)
701 except error.UnknownCommand:
701 except error.UnknownCommand:
702 pass
702 pass
703 raise error.ConfigError(self.badalias, hint=hint)
703 raise error.ConfigError(self.badalias, hint=hint)
704 if self.shadows:
704 if self.shadows:
705 ui.debug(
705 ui.debug(
706 b"alias '%s' shadows command '%s'\n" % (self.name, self.cmdname)
706 b"alias '%s' shadows command '%s'\n" % (self.name, self.cmdname)
707 )
707 )
708
708
709 ui.log(
709 ui.log(
710 b'commandalias',
710 b'commandalias',
711 b"alias '%s' expands to '%s'\n",
711 b"alias '%s' expands to '%s'\n",
712 self.name,
712 self.name,
713 self.definition,
713 self.definition,
714 )
714 )
715 if util.safehasattr(self, b'shell'):
715 if util.safehasattr(self, b'shell'):
716 return self.fn(ui, *args, **opts)
716 return self.fn(ui, *args, **opts)
717 else:
717 else:
718 try:
718 try:
719 return util.checksignature(self.fn)(ui, *args, **opts)
719 return util.checksignature(self.fn)(ui, *args, **opts)
720 except error.SignatureError:
720 except error.SignatureError:
721 args = b' '.join([self.cmdname] + self.args)
721 args = b' '.join([self.cmdname] + self.args)
722 ui.debug(b"alias '%s' expands to '%s'\n" % (self.name, args))
722 ui.debug(b"alias '%s' expands to '%s'\n" % (self.name, args))
723 raise
723 raise
724
724
725
725
726 class lazyaliasentry(object):
726 class lazyaliasentry(object):
727 """like a typical command entry (func, opts, help), but is lazy"""
727 """like a typical command entry (func, opts, help), but is lazy"""
728
728
729 def __init__(self, ui, name, definition, cmdtable, source):
729 def __init__(self, ui, name, definition, cmdtable, source):
730 self.ui = ui
730 self.ui = ui
731 self.name = name
731 self.name = name
732 self.definition = definition
732 self.definition = definition
733 self.cmdtable = cmdtable.copy()
733 self.cmdtable = cmdtable.copy()
734 self.source = source
734 self.source = source
735 self.alias = True
735 self.alias = True
736
736
737 @util.propertycache
737 @util.propertycache
738 def _aliasdef(self):
738 def _aliasdef(self):
739 return cmdalias(
739 return cmdalias(
740 self.ui, self.name, self.definition, self.cmdtable, self.source
740 self.ui, self.name, self.definition, self.cmdtable, self.source
741 )
741 )
742
742
743 def __getitem__(self, n):
743 def __getitem__(self, n):
744 aliasdef = self._aliasdef
744 aliasdef = self._aliasdef
745 if n == 0:
745 if n == 0:
746 return aliasdef
746 return aliasdef
747 elif n == 1:
747 elif n == 1:
748 return aliasdef.opts
748 return aliasdef.opts
749 elif n == 2:
749 elif n == 2:
750 return aliasdef.help
750 return aliasdef.help
751 else:
751 else:
752 raise IndexError
752 raise IndexError
753
753
754 def __iter__(self):
754 def __iter__(self):
755 for i in range(3):
755 for i in range(3):
756 yield self[i]
756 yield self[i]
757
757
758 def __len__(self):
758 def __len__(self):
759 return 3
759 return 3
760
760
761
761
762 def addaliases(ui, cmdtable):
762 def addaliases(ui, cmdtable):
763 # aliases are processed after extensions have been loaded, so they
763 # aliases are processed after extensions have been loaded, so they
764 # may use extension commands. Aliases can also use other alias definitions,
764 # may use extension commands. Aliases can also use other alias definitions,
765 # but only if they have been defined prior to the current definition.
765 # but only if they have been defined prior to the current definition.
766 for alias, definition in ui.configitems(b'alias', ignoresub=True):
766 for alias, definition in ui.configitems(b'alias', ignoresub=True):
767 try:
767 try:
768 if cmdtable[alias].definition == definition:
768 if cmdtable[alias].definition == definition:
769 continue
769 continue
770 except (KeyError, AttributeError):
770 except (KeyError, AttributeError):
771 # definition might not exist or it might not be a cmdalias
771 # definition might not exist or it might not be a cmdalias
772 pass
772 pass
773
773
774 source = ui.configsource(b'alias', alias)
774 source = ui.configsource(b'alias', alias)
775 entry = lazyaliasentry(ui, alias, definition, cmdtable, source)
775 entry = lazyaliasentry(ui, alias, definition, cmdtable, source)
776 cmdtable[alias] = entry
776 cmdtable[alias] = entry
777
777
778
778
779 def _parse(ui, args):
779 def _parse(ui, args):
780 options = {}
780 options = {}
781 cmdoptions = {}
781 cmdoptions = {}
782
782
783 try:
783 try:
784 args = fancyopts.fancyopts(args, commands.globalopts, options)
784 args = fancyopts.fancyopts(args, commands.globalopts, options)
785 except getopt.GetoptError as inst:
785 except getopt.GetoptError as inst:
786 raise error.CommandError(None, stringutil.forcebytestr(inst))
786 raise error.CommandError(None, stringutil.forcebytestr(inst))
787
787
788 if args:
788 if args:
789 cmd, args = args[0], args[1:]
789 cmd, args = args[0], args[1:]
790 aliases, entry = cmdutil.findcmd(
790 aliases, entry = cmdutil.findcmd(
791 cmd, commands.table, ui.configbool(b"ui", b"strict")
791 cmd, commands.table, ui.configbool(b"ui", b"strict")
792 )
792 )
793 cmd = aliases[0]
793 cmd = aliases[0]
794 args = aliasargs(entry[0], args)
794 args = aliasargs(entry[0], args)
795 defaults = ui.config(b"defaults", cmd)
795 defaults = ui.config(b"defaults", cmd)
796 if defaults:
796 if defaults:
797 args = (
797 args = (
798 pycompat.maplist(util.expandpath, pycompat.shlexsplit(defaults))
798 pycompat.maplist(util.expandpath, pycompat.shlexsplit(defaults))
799 + args
799 + args
800 )
800 )
801 c = list(entry[1])
801 c = list(entry[1])
802 else:
802 else:
803 cmd = None
803 cmd = None
804 c = []
804 c = []
805
805
806 # combine global options into local
806 # combine global options into local
807 for o in commands.globalopts:
807 for o in commands.globalopts:
808 c.append((o[0], o[1], options[o[1]], o[3]))
808 c.append((o[0], o[1], options[o[1]], o[3]))
809
809
810 try:
810 try:
811 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
811 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
812 except getopt.GetoptError as inst:
812 except getopt.GetoptError as inst:
813 raise error.CommandError(cmd, stringutil.forcebytestr(inst))
813 raise error.CommandError(cmd, stringutil.forcebytestr(inst))
814
814
815 # separate global options back out
815 # separate global options back out
816 for o in commands.globalopts:
816 for o in commands.globalopts:
817 n = o[1]
817 n = o[1]
818 options[n] = cmdoptions[n]
818 options[n] = cmdoptions[n]
819 del cmdoptions[n]
819 del cmdoptions[n]
820
820
821 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
821 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
822
822
823
823
824 def _parseconfig(ui, config):
824 def _parseconfig(ui, config):
825 """parse the --config options from the command line"""
825 """parse the --config options from the command line"""
826 configs = []
826 configs = []
827
827
828 for cfg in config:
828 for cfg in config:
829 try:
829 try:
830 name, value = [cfgelem.strip() for cfgelem in cfg.split(b'=', 1)]
830 name, value = [cfgelem.strip() for cfgelem in cfg.split(b'=', 1)]
831 section, name = name.split(b'.', 1)
831 section, name = name.split(b'.', 1)
832 if not section or not name:
832 if not section or not name:
833 raise IndexError
833 raise IndexError
834 ui.setconfig(section, name, value, b'--config')
834 ui.setconfig(section, name, value, b'--config')
835 configs.append((section, name, value))
835 configs.append((section, name, value))
836 except (IndexError, ValueError):
836 except (IndexError, ValueError):
837 raise error.Abort(
837 raise error.Abort(
838 _(
838 _(
839 b'malformed --config option: %r '
839 b'malformed --config option: %r '
840 b'(use --config section.name=value)'
840 b'(use --config section.name=value)'
841 )
841 )
842 % pycompat.bytestr(cfg)
842 % pycompat.bytestr(cfg)
843 )
843 )
844
844
845 return configs
845 return configs
846
846
847
847
848 def _earlyparseopts(ui, args):
848 def _earlyparseopts(ui, args):
849 options = {}
849 options = {}
850 fancyopts.fancyopts(
850 fancyopts.fancyopts(
851 args,
851 args,
852 commands.globalopts,
852 commands.globalopts,
853 options,
853 options,
854 gnu=not ui.plain(b'strictflags'),
854 gnu=not ui.plain(b'strictflags'),
855 early=True,
855 early=True,
856 optaliases={b'repository': [b'repo']},
856 optaliases={b'repository': [b'repo']},
857 )
857 )
858 return options
858 return options
859
859
860
860
861 def _earlysplitopts(args):
861 def _earlysplitopts(args):
862 """Split args into a list of possible early options and remainder args"""
862 """Split args into a list of possible early options and remainder args"""
863 shortoptions = b'R:'
863 shortoptions = b'R:'
864 # TODO: perhaps 'debugger' should be included
864 # TODO: perhaps 'debugger' should be included
865 longoptions = [b'cwd=', b'repository=', b'repo=', b'config=']
865 longoptions = [b'cwd=', b'repository=', b'repo=', b'config=']
866 return fancyopts.earlygetopt(
866 return fancyopts.earlygetopt(
867 args, shortoptions, longoptions, gnu=True, keepsep=True
867 args, shortoptions, longoptions, gnu=True, keepsep=True
868 )
868 )
869
869
870
870
871 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
871 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
872 # run pre-hook, and abort if it fails
872 # run pre-hook, and abort if it fails
873 hook.hook(
873 hook.hook(
874 lui,
874 lui,
875 repo,
875 repo,
876 b"pre-%s" % cmd,
876 b"pre-%s" % cmd,
877 True,
877 True,
878 args=b" ".join(fullargs),
878 args=b" ".join(fullargs),
879 pats=cmdpats,
879 pats=cmdpats,
880 opts=cmdoptions,
880 opts=cmdoptions,
881 )
881 )
882 try:
882 try:
883 ret = _runcommand(ui, options, cmd, d)
883 ret = _runcommand(ui, options, cmd, d)
884 # run post-hook, passing command result
884 # run post-hook, passing command result
885 hook.hook(
885 hook.hook(
886 lui,
886 lui,
887 repo,
887 repo,
888 b"post-%s" % cmd,
888 b"post-%s" % cmd,
889 False,
889 False,
890 args=b" ".join(fullargs),
890 args=b" ".join(fullargs),
891 result=ret,
891 result=ret,
892 pats=cmdpats,
892 pats=cmdpats,
893 opts=cmdoptions,
893 opts=cmdoptions,
894 )
894 )
895 except Exception:
895 except Exception:
896 # run failure hook and re-raise
896 # run failure hook and re-raise
897 hook.hook(
897 hook.hook(
898 lui,
898 lui,
899 repo,
899 repo,
900 b"fail-%s" % cmd,
900 b"fail-%s" % cmd,
901 False,
901 False,
902 args=b" ".join(fullargs),
902 args=b" ".join(fullargs),
903 pats=cmdpats,
903 pats=cmdpats,
904 opts=cmdoptions,
904 opts=cmdoptions,
905 )
905 )
906 raise
906 raise
907 return ret
907 return ret
908
908
909
909
910 def _readsharedsourceconfig(ui, path):
910 def _readsharedsourceconfig(ui, path):
911 """if the current repository is shared one, this tries to read
911 """if the current repository is shared one, this tries to read
912 .hg/hgrc of shared source if we are in share-safe mode
912 .hg/hgrc of shared source if we are in share-safe mode
913
913
914 Config read is loaded into the ui object passed
914 Config read is loaded into the ui object passed
915
915
916 This should be called before reading .hg/hgrc or the main repo
916 This should be called before reading .hg/hgrc or the main repo
917 as that overrides config set in shared source"""
917 as that overrides config set in shared source"""
918 try:
918 try:
919 with open(os.path.join(path, b".hg", b"requires"), "rb") as fp:
919 with open(os.path.join(path, b".hg", b"requires"), "rb") as fp:
920 requirements = set(fp.read().splitlines())
920 requirements = set(fp.read().splitlines())
921 if not (
921 if not (
922 requirementsmod.SHARESAFE_REQUIREMENT in requirements
922 requirementsmod.SHARESAFE_REQUIREMENT in requirements
923 and requirementsmod.SHARED_REQUIREMENT in requirements
923 and requirementsmod.SHARED_REQUIREMENT in requirements
924 ):
924 ):
925 return
925 return
926 hgvfs = vfs.vfs(os.path.join(path, b".hg"))
926 hgvfs = vfs.vfs(os.path.join(path, b".hg"))
927 sharedvfs = localrepo._getsharedvfs(hgvfs, requirements)
927 sharedvfs = localrepo._getsharedvfs(hgvfs, requirements)
928 root = sharedvfs.base
928 root = sharedvfs.base
929 ui.readconfig(sharedvfs.join(b"hgrc"), root)
929 ui.readconfig(sharedvfs.join(b"hgrc"), root)
930 except IOError:
930 except IOError:
931 pass
931 pass
932
932
933
933
934 def _getlocal(ui, rpath, wd=None):
934 def _getlocal(ui, rpath, wd=None):
935 """Return (path, local ui object) for the given target path.
935 """Return (path, local ui object) for the given target path.
936
936
937 Takes paths in [cwd]/.hg/hgrc into account."
937 Takes paths in [cwd]/.hg/hgrc into account."
938 """
938 """
939 if wd is None:
939 if wd is None:
940 try:
940 try:
941 wd = encoding.getcwd()
941 wd = encoding.getcwd()
942 except OSError as e:
942 except OSError as e:
943 raise error.Abort(
943 raise error.Abort(
944 _(b"error getting current working directory: %s")
944 _(b"error getting current working directory: %s")
945 % encoding.strtolocal(e.strerror)
945 % encoding.strtolocal(e.strerror)
946 )
946 )
947
947
948 path = cmdutil.findrepo(wd) or b""
948 path = cmdutil.findrepo(wd) or b""
949 if not path:
949 if not path:
950 lui = ui
950 lui = ui
951 else:
951 else:
952 lui = ui.copy()
952 lui = ui.copy()
953 if rcutil.use_repo_hgrc():
953 if rcutil.use_repo_hgrc():
954 _readsharedsourceconfig(lui, path)
954 _readsharedsourceconfig(lui, path)
955 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path)
955 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path)
956 lui.readconfig(os.path.join(path, b".hg", b"hgrc-not-shared"), path)
956 lui.readconfig(os.path.join(path, b".hg", b"hgrc-not-shared"), path)
957
957
958 if rpath:
958 if rpath:
959 path = lui.expandpath(rpath)
959 path = lui.expandpath(rpath)
960 lui = ui.copy()
960 lui = ui.copy()
961 if rcutil.use_repo_hgrc():
961 if rcutil.use_repo_hgrc():
962 _readsharedsourceconfig(lui, path)
962 _readsharedsourceconfig(lui, path)
963 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path)
963 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path)
964 lui.readconfig(os.path.join(path, b".hg", b"hgrc-not-shared"), path)
964 lui.readconfig(os.path.join(path, b".hg", b"hgrc-not-shared"), path)
965
965
966 return path, lui
966 return path, lui
967
967
968
968
969 def _checkshellalias(lui, ui, args):
969 def _checkshellalias(lui, ui, args):
970 """Return the function to run the shell alias, if it is required"""
970 """Return the function to run the shell alias, if it is required"""
971 options = {}
971 options = {}
972
972
973 try:
973 try:
974 args = fancyopts.fancyopts(args, commands.globalopts, options)
974 args = fancyopts.fancyopts(args, commands.globalopts, options)
975 except getopt.GetoptError:
975 except getopt.GetoptError:
976 return
976 return
977
977
978 if not args:
978 if not args:
979 return
979 return
980
980
981 cmdtable = commands.table
981 cmdtable = commands.table
982
982
983 cmd = args[0]
983 cmd = args[0]
984 try:
984 try:
985 strict = ui.configbool(b"ui", b"strict")
985 strict = ui.configbool(b"ui", b"strict")
986 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
986 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
987 except (error.AmbiguousCommand, error.UnknownCommand):
987 except (error.AmbiguousCommand, error.UnknownCommand):
988 return
988 return
989
989
990 cmd = aliases[0]
990 cmd = aliases[0]
991 fn = entry[0]
991 fn = entry[0]
992
992
993 if cmd and util.safehasattr(fn, b'shell'):
993 if cmd and util.safehasattr(fn, b'shell'):
994 # shell alias shouldn't receive early options which are consumed by hg
994 # shell alias shouldn't receive early options which are consumed by hg
995 _earlyopts, args = _earlysplitopts(args)
995 _earlyopts, args = _earlysplitopts(args)
996 d = lambda: fn(ui, *args[1:])
996 d = lambda: fn(ui, *args[1:])
997 return lambda: runcommand(
997 return lambda: runcommand(
998 lui, None, cmd, args[:1], ui, options, d, [], {}
998 lui, None, cmd, args[:1], ui, options, d, [], {}
999 )
999 )
1000
1000
1001
1001
1002 def _dispatch(req):
1002 def _dispatch(req):
1003 args = req.args
1003 args = req.args
1004 ui = req.ui
1004 ui = req.ui
1005
1005
1006 # check for cwd
1006 # check for cwd
1007 cwd = req.earlyoptions[b'cwd']
1007 cwd = req.earlyoptions[b'cwd']
1008 if cwd:
1008 if cwd:
1009 os.chdir(cwd)
1009 os.chdir(cwd)
1010
1010
1011 rpath = req.earlyoptions[b'repository']
1011 rpath = req.earlyoptions[b'repository']
1012 path, lui = _getlocal(ui, rpath)
1012 path, lui = _getlocal(ui, rpath)
1013
1013
1014 uis = {ui, lui}
1014 uis = {ui, lui}
1015
1015
1016 if req.repo:
1016 if req.repo:
1017 uis.add(req.repo.ui)
1017 uis.add(req.repo.ui)
1018
1018
1019 if (
1019 if (
1020 req.earlyoptions[b'verbose']
1020 req.earlyoptions[b'verbose']
1021 or req.earlyoptions[b'debug']
1021 or req.earlyoptions[b'debug']
1022 or req.earlyoptions[b'quiet']
1022 or req.earlyoptions[b'quiet']
1023 ):
1023 ):
1024 for opt in (b'verbose', b'debug', b'quiet'):
1024 for opt in (b'verbose', b'debug', b'quiet'):
1025 val = pycompat.bytestr(bool(req.earlyoptions[opt]))
1025 val = pycompat.bytestr(bool(req.earlyoptions[opt]))
1026 for ui_ in uis:
1026 for ui_ in uis:
1027 ui_.setconfig(b'ui', opt, val, b'--' + opt)
1027 ui_.setconfig(b'ui', opt, val, b'--' + opt)
1028
1028
1029 if req.earlyoptions[b'profile']:
1029 if req.earlyoptions[b'profile']:
1030 for ui_ in uis:
1030 for ui_ in uis:
1031 ui_.setconfig(b'profiling', b'enabled', b'true', b'--profile')
1031 ui_.setconfig(b'profiling', b'enabled', b'true', b'--profile')
1032
1032
1033 profile = lui.configbool(b'profiling', b'enabled')
1033 profile = lui.configbool(b'profiling', b'enabled')
1034 with profiling.profile(lui, enabled=profile) as profiler:
1034 with profiling.profile(lui, enabled=profile) as profiler:
1035 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
1035 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
1036 # reposetup
1036 # reposetup
1037 extensions.loadall(lui)
1037 extensions.loadall(lui)
1038 # Propagate any changes to lui.__class__ by extensions
1038 # Propagate any changes to lui.__class__ by extensions
1039 ui.__class__ = lui.__class__
1039 ui.__class__ = lui.__class__
1040
1040
1041 # (uisetup and extsetup are handled in extensions.loadall)
1041 # (uisetup and extsetup are handled in extensions.loadall)
1042
1042
1043 # (reposetup is handled in hg.repository)
1043 # (reposetup is handled in hg.repository)
1044
1044
1045 addaliases(lui, commands.table)
1045 addaliases(lui, commands.table)
1046
1046
1047 # All aliases and commands are completely defined, now.
1047 # All aliases and commands are completely defined, now.
1048 # Check abbreviation/ambiguity of shell alias.
1048 # Check abbreviation/ambiguity of shell alias.
1049 shellaliasfn = _checkshellalias(lui, ui, args)
1049 shellaliasfn = _checkshellalias(lui, ui, args)
1050 if shellaliasfn:
1050 if shellaliasfn:
1051 # no additional configs will be set, set up the ui instances
1051 # no additional configs will be set, set up the ui instances
1052 for ui_ in uis:
1052 for ui_ in uis:
1053 extensions.populateui(ui_)
1053 extensions.populateui(ui_)
1054 return shellaliasfn()
1054 return shellaliasfn()
1055
1055
1056 # check for fallback encoding
1056 # check for fallback encoding
1057 fallback = lui.config(b'ui', b'fallbackencoding')
1057 fallback = lui.config(b'ui', b'fallbackencoding')
1058 if fallback:
1058 if fallback:
1059 encoding.fallbackencoding = fallback
1059 encoding.fallbackencoding = fallback
1060
1060
1061 fullargs = args
1061 fullargs = args
1062 cmd, func, args, options, cmdoptions = _parse(lui, args)
1062 cmd, func, args, options, cmdoptions = _parse(lui, args)
1063
1063
1064 # store the canonical command name in request object for later access
1064 # store the canonical command name in request object for later access
1065 req.canonical_command = cmd
1065 req.canonical_command = cmd
1066
1066
1067 if options[b"config"] != req.earlyoptions[b"config"]:
1067 if options[b"config"] != req.earlyoptions[b"config"]:
1068 raise error.InputError(_(b"option --config may not be abbreviated"))
1068 raise error.InputError(_(b"option --config may not be abbreviated"))
1069 if options[b"cwd"] != req.earlyoptions[b"cwd"]:
1069 if options[b"cwd"] != req.earlyoptions[b"cwd"]:
1070 raise error.InputError(_(b"option --cwd may not be abbreviated"))
1070 raise error.InputError(_(b"option --cwd may not be abbreviated"))
1071 if options[b"repository"] != req.earlyoptions[b"repository"]:
1071 if options[b"repository"] != req.earlyoptions[b"repository"]:
1072 raise error.InputError(
1072 raise error.InputError(
1073 _(
1073 _(
1074 b"option -R has to be separated from other options (e.g. not "
1074 b"option -R has to be separated from other options (e.g. not "
1075 b"-qR) and --repository may only be abbreviated as --repo"
1075 b"-qR) and --repository may only be abbreviated as --repo"
1076 )
1076 )
1077 )
1077 )
1078 if options[b"debugger"] != req.earlyoptions[b"debugger"]:
1078 if options[b"debugger"] != req.earlyoptions[b"debugger"]:
1079 raise error.InputError(
1079 raise error.InputError(
1080 _(b"option --debugger may not be abbreviated")
1080 _(b"option --debugger may not be abbreviated")
1081 )
1081 )
1082 # don't validate --profile/--traceback, which can be enabled from now
1082 # don't validate --profile/--traceback, which can be enabled from now
1083
1083
1084 if options[b"encoding"]:
1084 if options[b"encoding"]:
1085 encoding.encoding = options[b"encoding"]
1085 encoding.encoding = options[b"encoding"]
1086 if options[b"encodingmode"]:
1086 if options[b"encodingmode"]:
1087 encoding.encodingmode = options[b"encodingmode"]
1087 encoding.encodingmode = options[b"encodingmode"]
1088 if options[b"time"]:
1088 if options[b"time"]:
1089
1089
1090 def get_times():
1090 def get_times():
1091 t = os.times()
1091 t = os.times()
1092 if t[4] == 0.0:
1092 if t[4] == 0.0:
1093 # Windows leaves this as zero, so use time.perf_counter()
1093 # Windows leaves this as zero, so use time.perf_counter()
1094 t = (t[0], t[1], t[2], t[3], util.timer())
1094 t = (t[0], t[1], t[2], t[3], util.timer())
1095 return t
1095 return t
1096
1096
1097 s = get_times()
1097 s = get_times()
1098
1098
1099 def print_time():
1099 def print_time():
1100 t = get_times()
1100 t = get_times()
1101 ui.warn(
1101 ui.warn(
1102 _(b"time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n")
1102 _(b"time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n")
1103 % (
1103 % (
1104 t[4] - s[4],
1104 t[4] - s[4],
1105 t[0] - s[0],
1105 t[0] - s[0],
1106 t[2] - s[2],
1106 t[2] - s[2],
1107 t[1] - s[1],
1107 t[1] - s[1],
1108 t[3] - s[3],
1108 t[3] - s[3],
1109 )
1109 )
1110 )
1110 )
1111
1111
1112 ui.atexit(print_time)
1112 ui.atexit(print_time)
1113 if options[b"profile"]:
1113 if options[b"profile"]:
1114 profiler.start()
1114 profiler.start()
1115
1115
1116 # if abbreviated version of this were used, take them in account, now
1116 # if abbreviated version of this were used, take them in account, now
1117 if options[b'verbose'] or options[b'debug'] or options[b'quiet']:
1117 if options[b'verbose'] or options[b'debug'] or options[b'quiet']:
1118 for opt in (b'verbose', b'debug', b'quiet'):
1118 for opt in (b'verbose', b'debug', b'quiet'):
1119 if options[opt] == req.earlyoptions[opt]:
1119 if options[opt] == req.earlyoptions[opt]:
1120 continue
1120 continue
1121 val = pycompat.bytestr(bool(options[opt]))
1121 val = pycompat.bytestr(bool(options[opt]))
1122 for ui_ in uis:
1122 for ui_ in uis:
1123 ui_.setconfig(b'ui', opt, val, b'--' + opt)
1123 ui_.setconfig(b'ui', opt, val, b'--' + opt)
1124
1124
1125 if options[b'traceback']:
1125 if options[b'traceback']:
1126 for ui_ in uis:
1126 for ui_ in uis:
1127 ui_.setconfig(b'ui', b'traceback', b'on', b'--traceback')
1127 ui_.setconfig(b'ui', b'traceback', b'on', b'--traceback')
1128
1128
1129 if options[b'noninteractive']:
1129 if options[b'noninteractive']:
1130 for ui_ in uis:
1130 for ui_ in uis:
1131 ui_.setconfig(b'ui', b'interactive', b'off', b'-y')
1131 ui_.setconfig(b'ui', b'interactive', b'off', b'-y')
1132
1132
1133 if cmdoptions.get(b'insecure', False):
1133 if cmdoptions.get(b'insecure', False):
1134 for ui_ in uis:
1134 for ui_ in uis:
1135 ui_.insecureconnections = True
1135 ui_.insecureconnections = True
1136
1136
1137 # setup color handling before pager, because setting up pager
1137 # setup color handling before pager, because setting up pager
1138 # might cause incorrect console information
1138 # might cause incorrect console information
1139 coloropt = options[b'color']
1139 coloropt = options[b'color']
1140 for ui_ in uis:
1140 for ui_ in uis:
1141 if coloropt:
1141 if coloropt:
1142 ui_.setconfig(b'ui', b'color', coloropt, b'--color')
1142 ui_.setconfig(b'ui', b'color', coloropt, b'--color')
1143 color.setup(ui_)
1143 color.setup(ui_)
1144
1144
1145 if stringutil.parsebool(options[b'pager']):
1145 if stringutil.parsebool(options[b'pager']):
1146 # ui.pager() expects 'internal-always-' prefix in this case
1146 # ui.pager() expects 'internal-always-' prefix in this case
1147 ui.pager(b'internal-always-' + cmd)
1147 ui.pager(b'internal-always-' + cmd)
1148 elif options[b'pager'] != b'auto':
1148 elif options[b'pager'] != b'auto':
1149 for ui_ in uis:
1149 for ui_ in uis:
1150 ui_.disablepager()
1150 ui_.disablepager()
1151
1151
1152 # configs are fully loaded, set up the ui instances
1152 # configs are fully loaded, set up the ui instances
1153 for ui_ in uis:
1153 for ui_ in uis:
1154 extensions.populateui(ui_)
1154 extensions.populateui(ui_)
1155
1155
1156 if options[b'version']:
1156 if options[b'version']:
1157 return commands.version_(ui)
1157 return commands.version_(ui)
1158 if options[b'help']:
1158 if options[b'help']:
1159 return commands.help_(ui, cmd, command=cmd is not None)
1159 return commands.help_(ui, cmd, command=cmd is not None)
1160 elif not cmd:
1160 elif not cmd:
1161 return commands.help_(ui, b'shortlist')
1161 return commands.help_(ui, b'shortlist')
1162
1162
1163 repo = None
1163 repo = None
1164 cmdpats = args[:]
1164 cmdpats = args[:]
1165 assert func is not None # help out pytype
1165 assert func is not None # help out pytype
1166 if not func.norepo:
1166 if not func.norepo:
1167 # use the repo from the request only if we don't have -R
1167 # use the repo from the request only if we don't have -R
1168 if not rpath and not cwd:
1168 if not rpath and not cwd:
1169 repo = req.repo
1169 repo = req.repo
1170
1170
1171 if repo:
1171 if repo:
1172 # set the descriptors of the repo ui to those of ui
1172 # set the descriptors of the repo ui to those of ui
1173 repo.ui.fin = ui.fin
1173 repo.ui.fin = ui.fin
1174 repo.ui.fout = ui.fout
1174 repo.ui.fout = ui.fout
1175 repo.ui.ferr = ui.ferr
1175 repo.ui.ferr = ui.ferr
1176 repo.ui.fmsg = ui.fmsg
1176 repo.ui.fmsg = ui.fmsg
1177 else:
1177 else:
1178 try:
1178 try:
1179 repo = hg.repository(
1179 repo = hg.repository(
1180 ui,
1180 ui,
1181 path=path,
1181 path=path,
1182 presetupfuncs=req.prereposetups,
1182 presetupfuncs=req.prereposetups,
1183 intents=func.intents,
1183 intents=func.intents,
1184 )
1184 )
1185 if not repo.local():
1185 if not repo.local():
1186 raise error.InputError(
1186 raise error.InputError(
1187 _(b"repository '%s' is not local") % path
1187 _(b"repository '%s' is not local") % path
1188 )
1188 )
1189 repo.ui.setconfig(
1189 repo.ui.setconfig(
1190 b"bundle", b"mainreporoot", repo.root, b'repo'
1190 b"bundle", b"mainreporoot", repo.root, b'repo'
1191 )
1191 )
1192 except error.RequirementError:
1192 except error.RequirementError:
1193 raise
1193 raise
1194 except error.RepoError:
1194 except error.RepoError:
1195 if rpath: # invalid -R path
1195 if rpath: # invalid -R path
1196 raise
1196 raise
1197 if not func.optionalrepo:
1197 if not func.optionalrepo:
1198 if func.inferrepo and args and not path:
1198 if func.inferrepo and args and not path:
1199 # try to infer -R from command args
1199 # try to infer -R from command args
1200 repos = pycompat.maplist(cmdutil.findrepo, args)
1200 repos = pycompat.maplist(cmdutil.findrepo, args)
1201 guess = repos[0]
1201 guess = repos[0]
1202 if guess and repos.count(guess) == len(repos):
1202 if guess and repos.count(guess) == len(repos):
1203 req.args = [b'--repository', guess] + fullargs
1203 req.args = [b'--repository', guess] + fullargs
1204 req.earlyoptions[b'repository'] = guess
1204 req.earlyoptions[b'repository'] = guess
1205 return _dispatch(req)
1205 return _dispatch(req)
1206 if not path:
1206 if not path:
1207 raise error.InputError(
1207 raise error.InputError(
1208 _(
1208 _(
1209 b"no repository found in"
1209 b"no repository found in"
1210 b" '%s' (.hg not found)"
1210 b" '%s' (.hg not found)"
1211 )
1211 )
1212 % encoding.getcwd()
1212 % encoding.getcwd()
1213 )
1213 )
1214 raise
1214 raise
1215 if repo:
1215 if repo:
1216 ui = repo.ui
1216 ui = repo.ui
1217 if options[b'hidden']:
1217 if options[b'hidden']:
1218 repo = repo.unfiltered()
1218 repo = repo.unfiltered()
1219 args.insert(0, repo)
1219 args.insert(0, repo)
1220 elif rpath:
1220 elif rpath:
1221 ui.warn(_(b"warning: --repository ignored\n"))
1221 ui.warn(_(b"warning: --repository ignored\n"))
1222
1222
1223 msg = _formatargs(fullargs)
1223 msg = _formatargs(fullargs)
1224 ui.log(b"command", b'%s\n', msg)
1224 ui.log(b"command", b'%s\n', msg)
1225 strcmdopt = pycompat.strkwargs(cmdoptions)
1225 strcmdopt = pycompat.strkwargs(cmdoptions)
1226 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
1226 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
1227 try:
1227 try:
1228 return runcommand(
1228 return runcommand(
1229 lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions
1229 lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions
1230 )
1230 )
1231 finally:
1231 finally:
1232 if repo and repo != req.repo:
1232 if repo and repo != req.repo:
1233 repo.close()
1233 repo.close()
1234
1234
1235
1235
1236 def _runcommand(ui, options, cmd, cmdfunc):
1236 def _runcommand(ui, options, cmd, cmdfunc):
1237 """Run a command function, possibly with profiling enabled."""
1237 """Run a command function, possibly with profiling enabled."""
1238 try:
1238 try:
1239 with tracing.log("Running %s command" % cmd):
1239 with tracing.log("Running %s command" % cmd):
1240 return cmdfunc()
1240 return cmdfunc()
1241 except error.SignatureError:
1241 except error.SignatureError:
1242 raise error.CommandError(cmd, _(b'invalid arguments'))
1242 raise error.CommandError(cmd, _(b'invalid arguments'))
1243
1243
1244
1244
1245 def _exceptionwarning(ui):
1245 def _exceptionwarning(ui):
1246 """Produce a warning message for the current active exception"""
1246 """Produce a warning message for the current active exception"""
1247
1247
1248 # For compatibility checking, we discard the portion of the hg
1248 # For compatibility checking, we discard the portion of the hg
1249 # version after the + on the assumption that if a "normal
1249 # version after the + on the assumption that if a "normal
1250 # user" is running a build with a + in it the packager
1250 # user" is running a build with a + in it the packager
1251 # probably built from fairly close to a tag and anyone with a
1251 # probably built from fairly close to a tag and anyone with a
1252 # 'make local' copy of hg (where the version number can be out
1252 # 'make local' copy of hg (where the version number can be out
1253 # of date) will be clueful enough to notice the implausible
1253 # of date) will be clueful enough to notice the implausible
1254 # version number and try updating.
1254 # version number and try updating.
1255 ct = util.versiontuple(n=2)
1255 ct = util.versiontuple(n=2)
1256 worst = None, ct, b''
1256 worst = None, ct, b'', b''
1257 if ui.config(b'ui', b'supportcontact') is None:
1257 if ui.config(b'ui', b'supportcontact') is None:
1258 for name, mod in extensions.extensions():
1258 for name, mod in extensions.extensions():
1259 # 'testedwith' should be bytes, but not all extensions are ported
1259 # 'testedwith' should be bytes, but not all extensions are ported
1260 # to py3 and we don't want UnicodeException because of that.
1260 # to py3 and we don't want UnicodeException because of that.
1261 testedwith = stringutil.forcebytestr(
1261 testedwith = stringutil.forcebytestr(
1262 getattr(mod, 'testedwith', b'')
1262 getattr(mod, 'testedwith', b'')
1263 )
1263 )
1264 version = extensions.moduleversion(mod)
1264 report = getattr(mod, 'buglink', _(b'the extension author.'))
1265 report = getattr(mod, 'buglink', _(b'the extension author.'))
1265 if not testedwith.strip():
1266 if not testedwith.strip():
1266 # We found an untested extension. It's likely the culprit.
1267 # We found an untested extension. It's likely the culprit.
1267 worst = name, b'unknown', report
1268 worst = name, b'unknown', report, version
1268 break
1269 break
1269
1270
1270 # Never blame on extensions bundled with Mercurial.
1271 # Never blame on extensions bundled with Mercurial.
1271 if extensions.ismoduleinternal(mod):
1272 if extensions.ismoduleinternal(mod):
1272 continue
1273 continue
1273
1274
1274 tested = [util.versiontuple(t, 2) for t in testedwith.split()]
1275 tested = [util.versiontuple(t, 2) for t in testedwith.split()]
1275 if ct in tested:
1276 if ct in tested:
1276 continue
1277 continue
1277
1278
1278 lower = [t for t in tested if t < ct]
1279 lower = [t for t in tested if t < ct]
1279 nearest = max(lower or tested)
1280 nearest = max(lower or tested)
1280 if worst[0] is None or nearest < worst[1]:
1281 if worst[0] is None or nearest < worst[1]:
1281 worst = name, nearest, report
1282 worst = name, nearest, report, version
1282 if worst[0] is not None:
1283 if worst[0] is not None:
1283 name, testedwith, report = worst
1284 name, testedwith, report, version = worst
1284 if not isinstance(testedwith, (bytes, str)):
1285 if not isinstance(testedwith, (bytes, str)):
1285 testedwith = b'.'.join(
1286 testedwith = b'.'.join(
1286 [stringutil.forcebytestr(c) for c in testedwith]
1287 [stringutil.forcebytestr(c) for c in testedwith]
1287 )
1288 )
1289 extver = version or _(b"(version N/A)")
1288 warning = _(
1290 warning = _(
1289 b'** Unknown exception encountered with '
1291 b'** Unknown exception encountered with '
1290 b'possibly-broken third-party extension %s\n'
1292 b'possibly-broken third-party extension %s %s\n'
1291 b'** which supports versions %s of Mercurial.\n'
1293 b'** which supports versions %s of Mercurial.\n'
1292 b'** Please disable %s and try your action again.\n'
1294 b'** Please disable %s and try your action again.\n'
1293 b'** If that fixes the bug please report it to %s\n'
1295 b'** If that fixes the bug please report it to %s\n'
1294 ) % (name, testedwith, name, stringutil.forcebytestr(report))
1296 ) % (name, extver, testedwith, name, stringutil.forcebytestr(report))
1295 else:
1297 else:
1296 bugtracker = ui.config(b'ui', b'supportcontact')
1298 bugtracker = ui.config(b'ui', b'supportcontact')
1297 if bugtracker is None:
1299 if bugtracker is None:
1298 bugtracker = _(b"https://mercurial-scm.org/wiki/BugTracker")
1300 bugtracker = _(b"https://mercurial-scm.org/wiki/BugTracker")
1299 warning = (
1301 warning = (
1300 _(
1302 _(
1301 b"** unknown exception encountered, "
1303 b"** unknown exception encountered, "
1302 b"please report by visiting\n** "
1304 b"please report by visiting\n** "
1303 )
1305 )
1304 + bugtracker
1306 + bugtracker
1305 + b'\n'
1307 + b'\n'
1306 )
1308 )
1307 sysversion = pycompat.sysbytes(sys.version).replace(b'\n', b'')
1309 sysversion = pycompat.sysbytes(sys.version).replace(b'\n', b'')
1308 warning += (
1310 warning += (
1309 (_(b"** Python %s\n") % sysversion)
1311 (_(b"** Python %s\n") % sysversion)
1310 + (_(b"** Mercurial Distributed SCM (version %s)\n") % util.version())
1312 + (_(b"** Mercurial Distributed SCM (version %s)\n") % util.version())
1311 + (
1313 + (
1312 _(b"** Extensions loaded: %s\n")
1314 _(b"** Extensions loaded: %s\n")
1313 % b", ".join([x[0] for x in extensions.extensions()])
1315 % b", ".join([x[0] for x in extensions.extensions()])
1314 )
1316 )
1315 )
1317 )
1316 return warning
1318 return warning
1317
1319
1318
1320
1319 def handlecommandexception(ui):
1321 def handlecommandexception(ui):
1320 """Produce a warning message for broken commands
1322 """Produce a warning message for broken commands
1321
1323
1322 Called when handling an exception; the exception is reraised if
1324 Called when handling an exception; the exception is reraised if
1323 this function returns False, ignored otherwise.
1325 this function returns False, ignored otherwise.
1324 """
1326 """
1325 warning = _exceptionwarning(ui)
1327 warning = _exceptionwarning(ui)
1326 ui.log(
1328 ui.log(
1327 b"commandexception",
1329 b"commandexception",
1328 b"%s\n%s\n",
1330 b"%s\n%s\n",
1329 warning,
1331 warning,
1330 pycompat.sysbytes(traceback.format_exc()),
1332 pycompat.sysbytes(traceback.format_exc()),
1331 )
1333 )
1332 ui.warn(warning)
1334 ui.warn(warning)
1333 return False # re-raise the exception
1335 return False # re-raise the exception
@@ -1,488 +1,488 b''
1 setup
1 setup
2
2
3 $ cat > myextension.py <<EOF
3 $ cat > myextension.py <<EOF
4 > from mercurial import error, registrar
4 > from mercurial import error, registrar
5 > cmdtable = {}
5 > cmdtable = {}
6 > command = registrar.command(cmdtable)
6 > command = registrar.command(cmdtable)
7 > @command(b'crash', [], b'hg crash')
7 > @command(b'crash', [], b'hg crash')
8 > def crash(ui, *args, **kwargs):
8 > def crash(ui, *args, **kwargs):
9 > raise Exception("oops")
9 > raise Exception("oops")
10 > @command(b'abortcmd', [], b'hg abortcmd')
10 > @command(b'abortcmd', [], b'hg abortcmd')
11 > def abort(ui, *args, **kwargs):
11 > def abort(ui, *args, **kwargs):
12 > raise error.Abort(b"oops")
12 > raise error.Abort(b"oops")
13 > EOF
13 > EOF
14 $ abspath=`pwd`/myextension.py
14 $ abspath=`pwd`/myextension.py
15
15
16 $ cat >> $HGRCPATH <<EOF
16 $ cat >> $HGRCPATH <<EOF
17 > [extensions]
17 > [extensions]
18 > blackbox=
18 > blackbox=
19 > mock=$TESTDIR/mockblackbox.py
19 > mock=$TESTDIR/mockblackbox.py
20 > mq=
20 > mq=
21 > myextension=$TESTTMP/myextension.py
21 > myextension=$TESTTMP/myextension.py
22 > [alias]
22 > [alias]
23 > confuse = log --limit 3
23 > confuse = log --limit 3
24 > so-confusing = confuse --style compact
24 > so-confusing = confuse --style compact
25 > EOF
25 > EOF
26
26
27 $ hg init blackboxtest
27 $ hg init blackboxtest
28 $ cd blackboxtest
28 $ cd blackboxtest
29
29
30 command, exit codes, and duration
30 command, exit codes, and duration
31
31
32 $ echo a > a
32 $ echo a > a
33 $ hg add a
33 $ hg add a
34 $ hg blackbox --config blackbox.dirty=True
34 $ hg blackbox --config blackbox.dirty=True
35 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest exited 0 after * seconds (glob)
35 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest exited 0 after * seconds (glob)
36 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
36 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
37 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
37 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
38 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox --config *blackbox.dirty=True* (glob)
38 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox --config *blackbox.dirty=True* (glob)
39
39
40 failure exit code
40 failure exit code
41 $ rm ./.hg/blackbox.log
41 $ rm ./.hg/blackbox.log
42 $ hg add non-existent
42 $ hg add non-existent
43 non-existent: $ENOENT$
43 non-existent: $ENOENT$
44 [1]
44 [1]
45 $ hg blackbox
45 $ hg blackbox
46 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add non-existent
46 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add non-existent
47 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add non-existent exited 1 after * seconds (glob)
47 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add non-existent exited 1 after * seconds (glob)
48 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
48 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
49
49
50 abort exit code
50 abort exit code
51 $ rm ./.hg/blackbox.log
51 $ rm ./.hg/blackbox.log
52 $ hg abortcmd 2> /dev/null
52 $ hg abortcmd 2> /dev/null
53 [255]
53 [255]
54 $ hg blackbox -l 2
54 $ hg blackbox -l 2
55 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> abortcmd exited 255 after * seconds (glob)
55 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> abortcmd exited 255 after * seconds (glob)
56 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox -l 2
56 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox -l 2
57
57
58 unhandled exception
58 unhandled exception
59 $ rm ./.hg/blackbox.log
59 $ rm ./.hg/blackbox.log
60 #if chg
60 #if chg
61 (chg exits 255 because it fails to receive an exit code)
61 (chg exits 255 because it fails to receive an exit code)
62 $ hg crash 2>/dev/null
62 $ hg crash 2>/dev/null
63 [255]
63 [255]
64 #else
64 #else
65 (hg exits 1 because Python default exit code for uncaught exception is 1)
65 (hg exits 1 because Python default exit code for uncaught exception is 1)
66 $ hg crash 2>/dev/null
66 $ hg crash 2>/dev/null
67 [1]
67 [1]
68 #endif
68 #endif
69 $ hg blackbox -l 2
69 $ hg blackbox -l 2
70 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> crash exited 1 after * seconds (glob)
70 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> crash exited 1 after * seconds (glob)
71 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox -l 2
71 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox -l 2
72
72
73 alias expansion is logged
73 alias expansion is logged
74 $ rm ./.hg/blackbox.log
74 $ rm ./.hg/blackbox.log
75 $ hg confuse
75 $ hg confuse
76 $ hg blackbox
76 $ hg blackbox
77 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse
77 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse
78 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
78 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
79 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse exited 0 after * seconds (glob)
79 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse exited 0 after * seconds (glob)
80 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
80 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
81
81
82 recursive aliases work correctly
82 recursive aliases work correctly
83 $ rm ./.hg/blackbox.log
83 $ rm ./.hg/blackbox.log
84 $ hg so-confusing
84 $ hg so-confusing
85 $ hg blackbox
85 $ hg blackbox
86 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing
86 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing
87 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'so-confusing' expands to 'confuse --style compact'
87 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'so-confusing' expands to 'confuse --style compact'
88 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
88 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
89 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing exited 0 after * seconds (glob)
89 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> so-confusing exited 0 after * seconds (glob)
90 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
90 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
91
91
92 custom date format
92 custom date format
93 $ rm ./.hg/blackbox.log
93 $ rm ./.hg/blackbox.log
94 $ hg --config blackbox.date-format='%Y-%m-%d @ %H:%M:%S' \
94 $ hg --config blackbox.date-format='%Y-%m-%d @ %H:%M:%S' \
95 > --config devel.default-date='1334347993 0' --traceback status
95 > --config devel.default-date='1334347993 0' --traceback status
96 A a
96 A a
97 $ hg blackbox
97 $ hg blackbox
98 2012-04-13 @ 20:13:13 bob @0000000000000000000000000000000000000000 (5000)> --config *blackbox.date-format=%Y-%m-%d @ %H:%M:%S* --config *devel.default-date=1334347993 0* --traceback status (glob)
98 2012-04-13 @ 20:13:13 bob @0000000000000000000000000000000000000000 (5000)> --config *blackbox.date-format=%Y-%m-%d @ %H:%M:%S* --config *devel.default-date=1334347993 0* --traceback status (glob)
99 2012-04-13 @ 20:13:13 bob @0000000000000000000000000000000000000000 (5000)> --config *blackbox.date-format=%Y-%m-%d @ %H:%M:%S* --config *devel.default-date=1334347993 0* --traceback status exited 0 after * seconds (glob)
99 2012-04-13 @ 20:13:13 bob @0000000000000000000000000000000000000000 (5000)> --config *blackbox.date-format=%Y-%m-%d @ %H:%M:%S* --config *devel.default-date=1334347993 0* --traceback status exited 0 after * seconds (glob)
100 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
100 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
101
101
102 incoming change tracking
102 incoming change tracking
103
103
104 create two heads to verify that we only see one change in the log later
104 create two heads to verify that we only see one change in the log later
105 $ hg commit -ma
105 $ hg commit -ma
106 $ hg up null
106 $ hg up null
107 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
107 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
108 $ echo b > b
108 $ echo b > b
109 $ hg commit -Amb
109 $ hg commit -Amb
110 adding b
110 adding b
111 created new head
111 created new head
112
112
113 clone, commit, pull
113 clone, commit, pull
114 $ hg clone . ../blackboxtest2
114 $ hg clone . ../blackboxtest2
115 updating to branch default
115 updating to branch default
116 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 $ echo c > c
117 $ echo c > c
118 $ hg commit -Amc
118 $ hg commit -Amc
119 adding c
119 adding c
120 $ cd ../blackboxtest2
120 $ cd ../blackboxtest2
121 $ hg pull
121 $ hg pull
122 pulling from $TESTTMP/blackboxtest
122 pulling from $TESTTMP/blackboxtest
123 searching for changes
123 searching for changes
124 adding changesets
124 adding changesets
125 adding manifests
125 adding manifests
126 adding file changes
126 adding file changes
127 added 1 changesets with 1 changes to 1 files
127 added 1 changesets with 1 changes to 1 files
128 new changesets d02f48003e62
128 new changesets d02f48003e62
129 (run 'hg update' to get a working copy)
129 (run 'hg update' to get a working copy)
130 $ hg blackbox -l 6
130 $ hg blackbox -l 6
131 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull
131 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull
132 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated branch cache (served) in * seconds (glob)
132 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated branch cache (served) in * seconds (glob)
133 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote branch cache (served) with 1 labels and 2 nodes
133 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote branch cache (served) with 1 labels and 2 nodes
134 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> 1 incoming changes - new heads: d02f48003e62
134 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> 1 incoming changes - new heads: d02f48003e62
135 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull exited 0 after * seconds (glob)
135 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull exited 0 after * seconds (glob)
136 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
136 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
137
137
138 we must not cause a failure if we cannot write to the log
138 we must not cause a failure if we cannot write to the log
139
139
140 $ hg rollback
140 $ hg rollback
141 repository tip rolled back to revision 1 (undo pull)
141 repository tip rolled back to revision 1 (undo pull)
142
142
143 $ mv .hg/blackbox.log .hg/blackbox.log-
143 $ mv .hg/blackbox.log .hg/blackbox.log-
144 $ mkdir .hg/blackbox.log
144 $ mkdir .hg/blackbox.log
145 $ hg --debug incoming
145 $ hg --debug incoming
146 warning: cannot write to blackbox.log: * (glob)
146 warning: cannot write to blackbox.log: * (glob)
147 comparing with $TESTTMP/blackboxtest
147 comparing with $TESTTMP/blackboxtest
148 query 1; heads
148 query 1; heads
149 searching for changes
149 searching for changes
150 all local changesets known remotely
150 all local changesets known remotely
151 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
151 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
152 tag: tip
152 tag: tip
153 phase: draft
153 phase: draft
154 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
154 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
155 parent: -1:0000000000000000000000000000000000000000
155 parent: -1:0000000000000000000000000000000000000000
156 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
156 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
157 user: test
157 user: test
158 date: Thu Jan 01 00:00:00 1970 +0000
158 date: Thu Jan 01 00:00:00 1970 +0000
159 files+: c
159 files+: c
160 extra: branch=default
160 extra: branch=default
161 description:
161 description:
162 c
162 c
163
163
164
164
165 $ hg pull
165 $ hg pull
166 pulling from $TESTTMP/blackboxtest
166 pulling from $TESTTMP/blackboxtest
167 searching for changes
167 searching for changes
168 adding changesets
168 adding changesets
169 adding manifests
169 adding manifests
170 adding file changes
170 adding file changes
171 added 1 changesets with 1 changes to 1 files
171 added 1 changesets with 1 changes to 1 files
172 new changesets d02f48003e62
172 new changesets d02f48003e62
173 (run 'hg update' to get a working copy)
173 (run 'hg update' to get a working copy)
174
174
175 a failure reading from the log is fatal
175 a failure reading from the log is fatal
176
176
177 $ hg blackbox -l 3
177 $ hg blackbox -l 3
178 abort: *$TESTTMP/blackboxtest2/.hg/blackbox.log* (glob)
178 abort: *$TESTTMP/blackboxtest2/.hg/blackbox.log* (glob)
179 [255]
179 [255]
180
180
181 $ rmdir .hg/blackbox.log
181 $ rmdir .hg/blackbox.log
182 $ mv .hg/blackbox.log- .hg/blackbox.log
182 $ mv .hg/blackbox.log- .hg/blackbox.log
183
183
184 backup bundles get logged
184 backup bundles get logged
185
185
186 $ touch d
186 $ touch d
187 $ hg commit -Amd
187 $ hg commit -Amd
188 adding d
188 adding d
189 created new head
189 created new head
190 $ hg strip tip
190 $ hg strip tip
191 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
191 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
192 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
192 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
193 $ hg blackbox -l 6
193 $ hg blackbox -l 6
194 1970/01/01 00:00:00 bob @73f6ee326b27d820b0472f1a825e3a50f3dc489b (5000)> strip tip
194 1970/01/01 00:00:00 bob @73f6ee326b27d820b0472f1a825e3a50f3dc489b (5000)> strip tip
195 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/73f6ee326b27-7612e004-backup.hg
195 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/73f6ee326b27-7612e004-backup.hg
196 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated branch cache (base) in * seconds (glob)
196 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated branch cache (base) in * seconds (glob)
197 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote branch cache (base) with 1 labels and 2 nodes
197 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote branch cache (base) with 1 labels and 2 nodes
198 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> strip tip exited 0 after * seconds (glob)
198 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> strip tip exited 0 after * seconds (glob)
199 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
199 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
200
200
201 extension and python hooks - use the eol extension for a pythonhook
201 extension and python hooks - use the eol extension for a pythonhook
202
202
203 $ echo '[extensions]' >> .hg/hgrc
203 $ echo '[extensions]' >> .hg/hgrc
204 $ echo 'eol=' >> .hg/hgrc
204 $ echo 'eol=' >> .hg/hgrc
205 $ echo '[hooks]' >> .hg/hgrc
205 $ echo '[hooks]' >> .hg/hgrc
206 $ echo 'update = echo hooked' >> .hg/hgrc
206 $ echo 'update = echo hooked' >> .hg/hgrc
207 $ hg update
207 $ hg update
208 The fsmonitor extension is incompatible with the eol extension and has been disabled. (fsmonitor !)
208 The fsmonitor extension is incompatible with the eol extension and has been disabled. (fsmonitor !)
209 hooked
209 hooked
210 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
211 updated to "d02f48003e62: c"
211 updated to "d02f48003e62: c"
212 1 other heads for branch "default"
212 1 other heads for branch "default"
213 $ cat >> .hg/hgrc <<EOF
213 $ cat >> .hg/hgrc <<EOF
214 > [extensions]
214 > [extensions]
215 > # disable eol, because it is not needed for subsequent tests
215 > # disable eol, because it is not needed for subsequent tests
216 > # (in addition, keeping it requires extra care for fsmonitor)
216 > # (in addition, keeping it requires extra care for fsmonitor)
217 > eol=!
217 > eol=!
218 > EOF
218 > EOF
219 $ hg blackbox -l 5
219 $ hg blackbox -l 5
220 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> update (no-chg !)
220 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> update (no-chg !)
221 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
221 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
222 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> exthook-update: echo hooked finished in * seconds (glob)
222 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> exthook-update: echo hooked finished in * seconds (glob)
223 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> update exited 0 after * seconds (glob)
223 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> update exited 0 after * seconds (glob)
224 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> serve --cmdserver chgunix --address $TESTTMP.chgsock/server.* --daemon-postexec 'chdir:/' (glob) (chg !)
224 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> serve --cmdserver chgunix --address $TESTTMP.chgsock/server.* --daemon-postexec 'chdir:/' (glob) (chg !)
225 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> blackbox -l 5
225 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> blackbox -l 5
226
226
227 log rotation
227 log rotation
228
228
229 $ echo '[blackbox]' >> .hg/hgrc
229 $ echo '[blackbox]' >> .hg/hgrc
230 $ echo 'maxsize = 20 b' >> .hg/hgrc
230 $ echo 'maxsize = 20 b' >> .hg/hgrc
231 $ echo 'maxfiles = 3' >> .hg/hgrc
231 $ echo 'maxfiles = 3' >> .hg/hgrc
232 $ hg status
232 $ hg status
233 $ hg status
233 $ hg status
234 $ hg status
234 $ hg status
235 $ hg tip -q
235 $ hg tip -q
236 2:d02f48003e62
236 2:d02f48003e62
237 $ ls .hg/blackbox.log*
237 $ ls .hg/blackbox.log*
238 .hg/blackbox.log
238 .hg/blackbox.log
239 .hg/blackbox.log.1
239 .hg/blackbox.log.1
240 .hg/blackbox.log.2
240 .hg/blackbox.log.2
241 $ cd ..
241 $ cd ..
242
242
243 $ hg init blackboxtest3
243 $ hg init blackboxtest3
244 $ cd blackboxtest3
244 $ cd blackboxtest3
245 $ hg blackbox
245 $ hg blackbox
246 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest3 exited 0 after * seconds (glob)
246 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> init blackboxtest3 exited 0 after * seconds (glob)
247 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
247 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
248 $ mv .hg/blackbox.log .hg/blackbox.log-
248 $ mv .hg/blackbox.log .hg/blackbox.log-
249 $ mkdir .hg/blackbox.log
249 $ mkdir .hg/blackbox.log
250 $ sed -e 's/\(.*test1.*\)/#\1/; s#\(.*commit2.*\)#os.rmdir(".hg/blackbox.log")\
250 $ sed -e 's/\(.*test1.*\)/#\1/; s#\(.*commit2.*\)#os.rmdir(".hg/blackbox.log")\
251 > os.rename(".hg/blackbox.log-", ".hg/blackbox.log")\
251 > os.rename(".hg/blackbox.log-", ".hg/blackbox.log")\
252 > \1#' $TESTDIR/test-dispatch.py > ../test-dispatch.py
252 > \1#' $TESTDIR/test-dispatch.py > ../test-dispatch.py
253 $ "$PYTHON" $TESTDIR/blackbox-readonly-dispatch.py
253 $ "$PYTHON" $TESTDIR/blackbox-readonly-dispatch.py
254 running: --debug add foo
254 running: --debug add foo
255 warning: cannot write to blackbox.log: Is a directory (no-windows !)
255 warning: cannot write to blackbox.log: Is a directory (no-windows !)
256 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
256 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
257 adding foo
257 adding foo
258 result: 0
258 result: 0
259 running: --debug commit -m commit1 -d 2000-01-01 foo
259 running: --debug commit -m commit1 -d 2000-01-01 foo
260 warning: cannot write to blackbox.log: Is a directory (no-windows !)
260 warning: cannot write to blackbox.log: Is a directory (no-windows !)
261 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
261 warning: cannot write to blackbox.log: $TESTTMP/blackboxtest3/.hg/blackbox.log: Access is denied (windows !)
262 committing files:
262 committing files:
263 foo
263 foo
264 committing manifest
264 committing manifest
265 committing changelog
265 committing changelog
266 updating the branch cache
266 updating the branch cache
267 committed changeset 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
267 committed changeset 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
268 result: 0
268 result: 0
269 running: --debug commit -m commit2 -d 2000-01-02 foo
269 running: --debug commit -m commit2 -d 2000-01-02 foo
270 committing files:
270 committing files:
271 foo
271 foo
272 committing manifest
272 committing manifest
273 committing changelog
273 committing changelog
274 updating the branch cache
274 updating the branch cache
275 committed changeset 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
275 committed changeset 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
276 result: 0
276 result: 0
277 running: --debug log -r 0
277 running: --debug log -r 0
278 changeset: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
278 changeset: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
279 phase: draft
279 phase: draft
280 parent: -1:0000000000000000000000000000000000000000
280 parent: -1:0000000000000000000000000000000000000000
281 parent: -1:0000000000000000000000000000000000000000
281 parent: -1:0000000000000000000000000000000000000000
282 manifest: 0:9091aa5df980aea60860a2e39c95182e68d1ddec
282 manifest: 0:9091aa5df980aea60860a2e39c95182e68d1ddec
283 user: test
283 user: test
284 date: Sat Jan 01 00:00:00 2000 +0000
284 date: Sat Jan 01 00:00:00 2000 +0000
285 files+: foo
285 files+: foo
286 extra: branch=default
286 extra: branch=default
287 description:
287 description:
288 commit1
288 commit1
289
289
290
290
291 result: 0
291 result: 0
292 running: --debug log -r tip
292 running: --debug log -r tip
293 changeset: 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
293 changeset: 1:45589e459b2edfbf3dbde7e01f611d2c1e7453d7
294 tag: tip
294 tag: tip
295 phase: draft
295 phase: draft
296 parent: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
296 parent: 0:0e46349438790c460c5c9f7546bfcd39b267bbd2
297 parent: -1:0000000000000000000000000000000000000000
297 parent: -1:0000000000000000000000000000000000000000
298 manifest: 1:895aa9b7886f89dd017a6d62524e1f9180b04df9
298 manifest: 1:895aa9b7886f89dd017a6d62524e1f9180b04df9
299 user: test
299 user: test
300 date: Sun Jan 02 00:00:00 2000 +0000
300 date: Sun Jan 02 00:00:00 2000 +0000
301 files: foo
301 files: foo
302 extra: branch=default
302 extra: branch=default
303 description:
303 description:
304 commit2
304 commit2
305
305
306
306
307 result: 0
307 result: 0
308 $ hg blackbox
308 $ hg blackbox
309 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updating the branch cache
309 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updating the branch cache
310 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updated branch cache (served) in * seconds (glob)
310 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> updated branch cache (served) in * seconds (glob)
311 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> wrote branch cache (served) with 1 labels and 1 nodes
311 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> wrote branch cache (served) with 1 labels and 1 nodes
312 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug commit -m commit2 -d 2000-01-02 foo exited 0 after *.?? seconds (glob)
312 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug commit -m commit2 -d 2000-01-02 foo exited 0 after *.?? seconds (glob)
313 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0
313 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0
314 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> writing .hg/cache/tags2-visible with 0 tags
314 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> writing .hg/cache/tags2-visible with 0 tags
315 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0 exited 0 after *.?? seconds (glob)
315 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r 0 exited 0 after *.?? seconds (glob)
316 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip
316 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip
317 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip exited 0 after *.?? seconds (glob)
317 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> --debug log -r tip exited 0 after *.?? seconds (glob)
318 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> blackbox
318 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> blackbox
319
319
320 Test log recursion from dirty status check
320 Test log recursion from dirty status check
321
321
322 $ cat > ../r.py <<EOF
322 $ cat > ../r.py <<EOF
323 > from mercurial import context, error, extensions
323 > from mercurial import context, error, extensions
324 > x=[False]
324 > x=[False]
325 > def status(orig, *args, **opts):
325 > def status(orig, *args, **opts):
326 > args[0].repo().ui.log(b"broken", b"recursion?")
326 > args[0].repo().ui.log(b"broken", b"recursion?")
327 > return orig(*args, **opts)
327 > return orig(*args, **opts)
328 > def reposetup(ui, repo):
328 > def reposetup(ui, repo):
329 > extensions.wrapfunction(context.basectx, 'status', status)
329 > extensions.wrapfunction(context.basectx, 'status', status)
330 > EOF
330 > EOF
331 $ hg id --config extensions.x=../r.py --config blackbox.dirty=True
331 $ hg id --config extensions.x=../r.py --config blackbox.dirty=True
332 45589e459b2e tip
332 45589e459b2e tip
333
333
334 cleanup
334 cleanup
335 $ cd ..
335 $ cd ..
336
336
337 Test missing log directory, which shouldn't be created automatically
337 Test missing log directory, which shouldn't be created automatically
338
338
339 $ cat <<'EOF' > closeremove.py
339 $ cat <<'EOF' > closeremove.py
340 > def reposetup(ui, repo):
340 > def reposetup(ui, repo):
341 > class rmrepo(repo.__class__):
341 > class rmrepo(repo.__class__):
342 > def close(self):
342 > def close(self):
343 > super(rmrepo, self).close()
343 > super(rmrepo, self).close()
344 > self.ui.debug(b'removing %s\n' % self.vfs.base)
344 > self.ui.debug(b'removing %s\n' % self.vfs.base)
345 > self.vfs.rmtree()
345 > self.vfs.rmtree()
346 > repo.__class__ = rmrepo
346 > repo.__class__ = rmrepo
347 > EOF
347 > EOF
348
348
349 $ hg init gone
349 $ hg init gone
350 $ cd gone
350 $ cd gone
351 $ cat <<'EOF' > .hg/hgrc
351 $ cat <<'EOF' > .hg/hgrc
352 > [extensions]
352 > [extensions]
353 > closeremove = ../closeremove.py
353 > closeremove = ../closeremove.py
354 > EOF
354 > EOF
355 $ hg log --debug
355 $ hg log --debug
356 removing $TESTTMP/gone/.hg
356 removing $TESTTMP/gone/.hg
357 warning: cannot write to blackbox.log: $ENOENT$ (no-windows !)
357 warning: cannot write to blackbox.log: $ENOENT$ (no-windows !)
358 warning: cannot write to blackbox.log: $TESTTMP/gone/.hg/blackbox.log: $ENOTDIR$ (windows !)
358 warning: cannot write to blackbox.log: $TESTTMP/gone/.hg/blackbox.log: $ENOTDIR$ (windows !)
359 $ cd ..
359 $ cd ..
360
360
361 blackbox should disable itself if track is empty
361 blackbox should disable itself if track is empty
362
362
363 $ hg --config blackbox.track= init nothing_tracked
363 $ hg --config blackbox.track= init nothing_tracked
364 $ cd nothing_tracked
364 $ cd nothing_tracked
365 $ cat >> .hg/hgrc << EOF
365 $ cat >> .hg/hgrc << EOF
366 > [blackbox]
366 > [blackbox]
367 > track =
367 > track =
368 > EOF
368 > EOF
369 $ hg blackbox
369 $ hg blackbox
370 $ cd $TESTTMP
370 $ cd $TESTTMP
371
371
372 a '*' entry in blackbox.track is interpreted as log everything
372 a '*' entry in blackbox.track is interpreted as log everything
373
373
374 $ hg --config blackbox.track='*' \
374 $ hg --config blackbox.track='*' \
375 > --config blackbox.logsource=True \
375 > --config blackbox.logsource=True \
376 > init track_star
376 > init track_star
377 $ cd track_star
377 $ cd track_star
378 $ cat >> .hg/hgrc << EOF
378 $ cat >> .hg/hgrc << EOF
379 > [blackbox]
379 > [blackbox]
380 > logsource = True
380 > logsource = True
381 > track = *
381 > track = *
382 > EOF
382 > EOF
383 (only look for entries with specific logged sources, otherwise this test is
383 (only look for entries with specific logged sources, otherwise this test is
384 pretty brittle)
384 pretty brittle)
385 $ hg blackbox | egrep '\[command(finish)?\]'
385 $ hg blackbox | egrep '\[command(finish)?\]'
386 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000) [commandfinish]> --config *blackbox.track=* --config *blackbox.logsource=True* init track_star exited 0 after * seconds (glob)
386 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000) [commandfinish]> --config *blackbox.track=* --config *blackbox.logsource=True* init track_star exited 0 after * seconds (glob)
387 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000) [command]> blackbox
387 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000) [command]> blackbox
388 $ cd $TESTTMP
388 $ cd $TESTTMP
389
389
390 #if chg
390 #if chg
391
391
392 when using chg, blackbox.log should get rotated correctly
392 when using chg, blackbox.log should get rotated correctly
393
393
394 $ cat > $TESTTMP/noop.py << EOF
394 $ cat > $TESTTMP/noop.py << EOF
395 > from __future__ import absolute_import
395 > from __future__ import absolute_import
396 > import time
396 > import time
397 > from mercurial import registrar, scmutil
397 > from mercurial import registrar, scmutil
398 > cmdtable = {}
398 > cmdtable = {}
399 > command = registrar.command(cmdtable)
399 > command = registrar.command(cmdtable)
400 > @command(b'noop')
400 > @command(b'noop')
401 > def noop(ui, repo):
401 > def noop(ui, repo):
402 > pass
402 > pass
403 > EOF
403 > EOF
404
404
405 $ hg init blackbox-chg
405 $ hg init blackbox-chg
406 $ cd blackbox-chg
406 $ cd blackbox-chg
407
407
408 $ cat > .hg/hgrc << EOF
408 $ cat > .hg/hgrc << EOF
409 > [blackbox]
409 > [blackbox]
410 > maxsize = 500B
410 > maxsize = 500B
411 > [extensions]
411 > [extensions]
412 > # extension change forces chg to restart
412 > # extension change forces chg to restart
413 > noop=$TESTTMP/noop.py
413 > noop=$TESTTMP/noop.py
414 > EOF
414 > EOF
415
415
416 $ "$PYTHON" -c 'print("a" * 400)' > .hg/blackbox.log
416 $ "$PYTHON" -c 'print("a" * 400)' > .hg/blackbox.log
417 $ chg noop
417 $ chg noop
418 $ chg noop
418 $ chg noop
419 $ chg noop
419 $ chg noop
420 $ chg noop
420 $ chg noop
421 $ chg noop
421 $ chg noop
422
422
423 $ cat > showsize.py << 'EOF'
423 $ cat > showsize.py << 'EOF'
424 > import os
424 > import os
425 > import sys
425 > import sys
426 > limit = 500
426 > limit = 500
427 > for p in sys.argv[1:]:
427 > for p in sys.argv[1:]:
428 > size = os.stat(p).st_size
428 > size = os.stat(p).st_size
429 > if size >= limit:
429 > if size >= limit:
430 > desc = '>='
430 > desc = '>='
431 > else:
431 > else:
432 > desc = '<'
432 > desc = '<'
433 > print('%s: %s %d' % (p, desc, limit))
433 > print('%s: %s %d' % (p, desc, limit))
434 > EOF
434 > EOF
435
435
436 $ "$PYTHON" showsize.py .hg/blackbox*
436 $ "$PYTHON" showsize.py .hg/blackbox*
437 .hg/blackbox.log: < 500
437 .hg/blackbox.log: < 500
438 .hg/blackbox.log.1: >= 500
438 .hg/blackbox.log.1: >= 500
439 .hg/blackbox.log.2: >= 500
439 .hg/blackbox.log.2: >= 500
440
440
441 $ cd ..
441 $ cd ..
442
442
443 With chg, blackbox should not create the log file if the repo is gone
443 With chg, blackbox should not create the log file if the repo is gone
444
444
445 $ hg init repo1
445 $ hg init repo1
446 $ hg --config extensions.a=! -R repo1 log
446 $ hg --config extensions.a=! -R repo1 log
447 $ rm -rf $TESTTMP/repo1
447 $ rm -rf $TESTTMP/repo1
448 $ hg --config extensions.a=! init repo1
448 $ hg --config extensions.a=! init repo1
449
449
450 #endif
450 #endif
451
451
452 blackbox should work if repo.ui.log is not called (issue5518)
452 blackbox should work if repo.ui.log is not called (issue5518)
453
453
454 $ cat > $TESTTMP/raise.py << EOF
454 $ cat > $TESTTMP/raise.py << EOF
455 > from __future__ import absolute_import
455 > from __future__ import absolute_import
456 > from mercurial import registrar, scmutil
456 > from mercurial import registrar, scmutil
457 > cmdtable = {}
457 > cmdtable = {}
458 > command = registrar.command(cmdtable)
458 > command = registrar.command(cmdtable)
459 > @command(b'raise')
459 > @command(b'raise')
460 > def raisecmd(*args):
460 > def raisecmd(*args):
461 > raise RuntimeError('raise')
461 > raise RuntimeError('raise')
462 > EOF
462 > EOF
463
463
464 $ cat >> $HGRCPATH << EOF
464 $ cat >> $HGRCPATH << EOF
465 > [blackbox]
465 > [blackbox]
466 > track = commandexception
466 > track = commandexception
467 > [extensions]
467 > [extensions]
468 > raise=$TESTTMP/raise.py
468 > raise=$TESTTMP/raise.py
469 > EOF
469 > EOF
470
470
471 $ hg init $TESTTMP/blackbox-exception-only
471 $ hg init $TESTTMP/blackbox-exception-only
472 $ cd $TESTTMP/blackbox-exception-only
472 $ cd $TESTTMP/blackbox-exception-only
473
473
474 #if chg
474 #if chg
475 (chg exits 255 because it fails to receive an exit code)
475 (chg exits 255 because it fails to receive an exit code)
476 $ hg raise 2>/dev/null
476 $ hg raise 2>/dev/null
477 [255]
477 [255]
478 #else
478 #else
479 (hg exits 1 because Python default exit code for uncaught exception is 1)
479 (hg exits 1 because Python default exit code for uncaught exception is 1)
480 $ hg raise 2>/dev/null
480 $ hg raise 2>/dev/null
481 [1]
481 [1]
482 #endif
482 #endif
483
483
484 $ head -1 .hg/blackbox.log
484 $ head -1 .hg/blackbox.log
485 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> ** Unknown exception encountered with possibly-broken third-party extension mock
485 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> ** Unknown exception encountered with possibly-broken third-party extension mock (version N/A)
486 $ tail -2 .hg/blackbox.log
486 $ tail -2 .hg/blackbox.log
487 RuntimeError: raise
487 RuntimeError: raise
488
488
@@ -1,393 +1,393 b''
1
1
2 $ cat << EOF > buggylocking.py
2 $ cat << EOF > buggylocking.py
3 > """A small extension that tests our developer warnings
3 > """A small extension that tests our developer warnings
4 > """
4 > """
5 >
5 >
6 > from mercurial import error, registrar, repair, util
6 > from mercurial import error, registrar, repair, util
7 >
7 >
8 > cmdtable = {}
8 > cmdtable = {}
9 > command = registrar.command(cmdtable)
9 > command = registrar.command(cmdtable)
10 >
10 >
11 > @command(b'buggylocking', [], '')
11 > @command(b'buggylocking', [], '')
12 > def buggylocking(ui, repo):
12 > def buggylocking(ui, repo):
13 > lo = repo.lock()
13 > lo = repo.lock()
14 > wl = repo.wlock()
14 > wl = repo.wlock()
15 > wl.release()
15 > wl.release()
16 > lo.release()
16 > lo.release()
17 >
17 >
18 > @command(b'buggytransaction', [], '')
18 > @command(b'buggytransaction', [], '')
19 > def buggylocking(ui, repo):
19 > def buggylocking(ui, repo):
20 > tr = repo.transaction(b'buggy')
20 > tr = repo.transaction(b'buggy')
21 > # make sure we rollback the transaction as we don't want to rely on the__del__
21 > # make sure we rollback the transaction as we don't want to rely on the__del__
22 > tr.release()
22 > tr.release()
23 >
23 >
24 > @command(b'properlocking', [], '')
24 > @command(b'properlocking', [], '')
25 > def properlocking(ui, repo):
25 > def properlocking(ui, repo):
26 > """check that reentrance is fine"""
26 > """check that reentrance is fine"""
27 > wl = repo.wlock()
27 > wl = repo.wlock()
28 > lo = repo.lock()
28 > lo = repo.lock()
29 > tr = repo.transaction(b'proper')
29 > tr = repo.transaction(b'proper')
30 > tr2 = repo.transaction(b'proper')
30 > tr2 = repo.transaction(b'proper')
31 > lo2 = repo.lock()
31 > lo2 = repo.lock()
32 > wl2 = repo.wlock()
32 > wl2 = repo.wlock()
33 > wl2.release()
33 > wl2.release()
34 > lo2.release()
34 > lo2.release()
35 > tr2.close()
35 > tr2.close()
36 > tr.close()
36 > tr.close()
37 > lo.release()
37 > lo.release()
38 > wl.release()
38 > wl.release()
39 >
39 >
40 > @command(b'nowaitlocking', [], '')
40 > @command(b'nowaitlocking', [], '')
41 > def nowaitlocking(ui, repo):
41 > def nowaitlocking(ui, repo):
42 > lo = repo.lock()
42 > lo = repo.lock()
43 > wl = repo.wlock(wait=False)
43 > wl = repo.wlock(wait=False)
44 > wl.release()
44 > wl.release()
45 > lo.release()
45 > lo.release()
46 >
46 >
47 > @command(b'no-wlock-write', [], '')
47 > @command(b'no-wlock-write', [], '')
48 > def nowlockwrite(ui, repo):
48 > def nowlockwrite(ui, repo):
49 > with repo.vfs(b'branch', b'a'):
49 > with repo.vfs(b'branch', b'a'):
50 > pass
50 > pass
51 >
51 >
52 > @command(b'no-lock-write', [], '')
52 > @command(b'no-lock-write', [], '')
53 > def nolockwrite(ui, repo):
53 > def nolockwrite(ui, repo):
54 > with repo.svfs(b'fncache', b'a'):
54 > with repo.svfs(b'fncache', b'a'):
55 > pass
55 > pass
56 >
56 >
57 > @command(b'stripintr', [], '')
57 > @command(b'stripintr', [], '')
58 > def stripintr(ui, repo):
58 > def stripintr(ui, repo):
59 > lo = repo.lock()
59 > lo = repo.lock()
60 > tr = repo.transaction(b'foobar')
60 > tr = repo.transaction(b'foobar')
61 > try:
61 > try:
62 > repair.strip(repo.ui, repo, [repo[b'.'].node()])
62 > repair.strip(repo.ui, repo, [repo[b'.'].node()])
63 > finally:
63 > finally:
64 > lo.release()
64 > lo.release()
65 > @command(b'oldanddeprecated', [], '')
65 > @command(b'oldanddeprecated', [], '')
66 > def oldanddeprecated(ui, repo):
66 > def oldanddeprecated(ui, repo):
67 > """test deprecation warning API"""
67 > """test deprecation warning API"""
68 > def foobar(ui):
68 > def foobar(ui):
69 > ui.deprecwarn(b'foorbar is deprecated, go shopping', b'42.1337')
69 > ui.deprecwarn(b'foorbar is deprecated, go shopping', b'42.1337')
70 > foobar(ui)
70 > foobar(ui)
71 > @command(b'nouiwarning', [], '')
71 > @command(b'nouiwarning', [], '')
72 > def nouiwarning(ui, repo):
72 > def nouiwarning(ui, repo):
73 > util.nouideprecwarn(b'this is a test', b'13.37')
73 > util.nouideprecwarn(b'this is a test', b'13.37')
74 > @command(b'programmingerror', [], '')
74 > @command(b'programmingerror', [], '')
75 > def programmingerror(ui, repo):
75 > def programmingerror(ui, repo):
76 > raise error.ProgrammingError(b'something went wrong', hint=b'try again')
76 > raise error.ProgrammingError(b'something went wrong', hint=b'try again')
77 > EOF
77 > EOF
78
78
79 $ cat << EOF >> $HGRCPATH
79 $ cat << EOF >> $HGRCPATH
80 > [extensions]
80 > [extensions]
81 > buggylocking=$TESTTMP/buggylocking.py
81 > buggylocking=$TESTTMP/buggylocking.py
82 > mock=$TESTDIR/mockblackbox.py
82 > mock=$TESTDIR/mockblackbox.py
83 > blackbox=
83 > blackbox=
84 > [devel]
84 > [devel]
85 > all-warnings=1
85 > all-warnings=1
86 > [blackbox]
86 > [blackbox]
87 > track = command, commandexception, commandfinish, develwarn
87 > track = command, commandexception, commandfinish, develwarn
88 > EOF
88 > EOF
89
89
90 $ hg init lock-checker
90 $ hg init lock-checker
91 $ cd lock-checker
91 $ cd lock-checker
92 $ hg buggylocking
92 $ hg buggylocking
93 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
93 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
94 $ cat << EOF >> $HGRCPATH
94 $ cat << EOF >> $HGRCPATH
95 > [devel]
95 > [devel]
96 > all=0
96 > all=0
97 > check-locks=1
97 > check-locks=1
98 > EOF
98 > EOF
99 $ hg buggylocking
99 $ hg buggylocking
100 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
100 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
101 #if no-chg
101 #if no-chg
102 $ hg buggylocking --traceback
102 $ hg buggylocking --traceback
103 devel-warn: "wlock" acquired after "lock" at:
103 devel-warn: "wlock" acquired after "lock" at:
104 */hg:* in <module> (glob) (?)
104 */hg:* in <module> (glob) (?)
105 */mercurial/dispatch.py:* in run (glob)
105 */mercurial/dispatch.py:* in run (glob)
106 */mercurial/dispatch.py:* in dispatch (glob)
106 */mercurial/dispatch.py:* in dispatch (glob)
107 */mercurial/dispatch.py:* in _runcatch (glob)
107 */mercurial/dispatch.py:* in _runcatch (glob)
108 */mercurial/dispatch.py:* in _callcatch (glob)
108 */mercurial/dispatch.py:* in _callcatch (glob)
109 */mercurial/scmutil.py* in callcatch (glob)
109 */mercurial/scmutil.py* in callcatch (glob)
110 */mercurial/dispatch.py:* in _runcatchfunc (glob)
110 */mercurial/dispatch.py:* in _runcatchfunc (glob)
111 */mercurial/dispatch.py:* in _dispatch (glob)
111 */mercurial/dispatch.py:* in _dispatch (glob)
112 */mercurial/dispatch.py:* in runcommand (glob)
112 */mercurial/dispatch.py:* in runcommand (glob)
113 */mercurial/dispatch.py:* in _runcommand (glob)
113 */mercurial/dispatch.py:* in _runcommand (glob)
114 */mercurial/dispatch.py:* in <lambda> (glob)
114 */mercurial/dispatch.py:* in <lambda> (glob)
115 */mercurial/util.py:* in check (glob)
115 */mercurial/util.py:* in check (glob)
116 $TESTTMP/buggylocking.py:* in buggylocking (glob)
116 $TESTTMP/buggylocking.py:* in buggylocking (glob)
117 #else
117 #else
118 $ hg buggylocking --traceback
118 $ hg buggylocking --traceback
119 devel-warn: "wlock" acquired after "lock" at:
119 devel-warn: "wlock" acquired after "lock" at:
120 */hg:* in <module> (glob) (?)
120 */hg:* in <module> (glob) (?)
121 */mercurial/dispatch.py:* in run (glob)
121 */mercurial/dispatch.py:* in run (glob)
122 */mercurial/dispatch.py:* in dispatch (glob)
122 */mercurial/dispatch.py:* in dispatch (glob)
123 */mercurial/dispatch.py:* in _runcatch (glob)
123 */mercurial/dispatch.py:* in _runcatch (glob)
124 */mercurial/dispatch.py:* in _callcatch (glob)
124 */mercurial/dispatch.py:* in _callcatch (glob)
125 */mercurial/scmutil.py:* in callcatch (glob)
125 */mercurial/scmutil.py:* in callcatch (glob)
126 */mercurial/dispatch.py:* in _runcatchfunc (glob)
126 */mercurial/dispatch.py:* in _runcatchfunc (glob)
127 */mercurial/dispatch.py:* in _dispatch (glob)
127 */mercurial/dispatch.py:* in _dispatch (glob)
128 */mercurial/dispatch.py:* in runcommand (glob)
128 */mercurial/dispatch.py:* in runcommand (glob)
129 */mercurial/dispatch.py:* in _runcommand (glob)
129 */mercurial/dispatch.py:* in _runcommand (glob)
130 */mercurial/dispatch.py:* in <lambda> (glob)
130 */mercurial/dispatch.py:* in <lambda> (glob)
131 */mercurial/util.py:* in check (glob)
131 */mercurial/util.py:* in check (glob)
132 */mercurial/commands.py:* in serve (glob)
132 */mercurial/commands.py:* in serve (glob)
133 */mercurial/server.py:* in runservice (glob)
133 */mercurial/server.py:* in runservice (glob)
134 */mercurial/commandserver.py:* in run (glob)
134 */mercurial/commandserver.py:* in run (glob)
135 */mercurial/commandserver.py:* in _mainloop (glob)
135 */mercurial/commandserver.py:* in _mainloop (glob)
136 */mercurial/commandserver.py:* in _acceptnewconnection (glob)
136 */mercurial/commandserver.py:* in _acceptnewconnection (glob)
137 */mercurial/commandserver.py:* in _runworker (glob)
137 */mercurial/commandserver.py:* in _runworker (glob)
138 */mercurial/commandserver.py:* in _serverequest (glob)
138 */mercurial/commandserver.py:* in _serverequest (glob)
139 */mercurial/commandserver.py:* in serve (glob)
139 */mercurial/commandserver.py:* in serve (glob)
140 */mercurial/commandserver.py:* in serveone (glob)
140 */mercurial/commandserver.py:* in serveone (glob)
141 */mercurial/chgserver.py:* in runcommand (glob)
141 */mercurial/chgserver.py:* in runcommand (glob)
142 */mercurial/commandserver.py:* in runcommand (glob)
142 */mercurial/commandserver.py:* in runcommand (glob)
143 */mercurial/commandserver.py:* in _dispatchcommand (glob)
143 */mercurial/commandserver.py:* in _dispatchcommand (glob)
144 */mercurial/dispatch.py:* in dispatch (glob)
144 */mercurial/dispatch.py:* in dispatch (glob)
145 */mercurial/dispatch.py:* in _runcatch (glob)
145 */mercurial/dispatch.py:* in _runcatch (glob)
146 */mercurial/dispatch.py:* in _callcatch (glob)
146 */mercurial/dispatch.py:* in _callcatch (glob)
147 */mercurial/scmutil.py:* in callcatch (glob)
147 */mercurial/scmutil.py:* in callcatch (glob)
148 */mercurial/dispatch.py:* in _runcatchfunc (glob)
148 */mercurial/dispatch.py:* in _runcatchfunc (glob)
149 */mercurial/dispatch.py:* in _dispatch (glob)
149 */mercurial/dispatch.py:* in _dispatch (glob)
150 */mercurial/dispatch.py:* in runcommand (glob)
150 */mercurial/dispatch.py:* in runcommand (glob)
151 */mercurial/dispatch.py:* in _runcommand (glob)
151 */mercurial/dispatch.py:* in _runcommand (glob)
152 */mercurial/dispatch.py:* in <lambda> (glob)
152 */mercurial/dispatch.py:* in <lambda> (glob)
153 */mercurial/util.py:* in check (glob)
153 */mercurial/util.py:* in check (glob)
154 $TESTTMP/buggylocking.py:* in buggylocking (glob)
154 $TESTTMP/buggylocking.py:* in buggylocking (glob)
155 #endif
155 #endif
156 $ hg properlocking
156 $ hg properlocking
157 $ hg nowaitlocking
157 $ hg nowaitlocking
158
158
159 Writing without lock
159 Writing without lock
160
160
161 $ hg no-wlock-write
161 $ hg no-wlock-write
162 devel-warn: write with no wlock: "branch" at: $TESTTMP/buggylocking.py:* (nowlockwrite) (glob)
162 devel-warn: write with no wlock: "branch" at: $TESTTMP/buggylocking.py:* (nowlockwrite) (glob)
163
163
164 $ hg no-lock-write
164 $ hg no-lock-write
165 devel-warn: write with no lock: "fncache" at: $TESTTMP/buggylocking.py:* (nolockwrite) (glob)
165 devel-warn: write with no lock: "fncache" at: $TESTTMP/buggylocking.py:* (nolockwrite) (glob)
166
166
167 Stripping from a transaction
167 Stripping from a transaction
168
168
169 $ echo a > a
169 $ echo a > a
170 $ hg add a
170 $ hg add a
171 $ hg commit -m a
171 $ hg commit -m a
172 $ hg stripintr 2>&1 | egrep -v '^(\*\*| )'
172 $ hg stripintr 2>&1 | egrep -v '^(\*\*| )'
173 Traceback (most recent call last):
173 Traceback (most recent call last):
174 *ProgrammingError: cannot strip from inside a transaction (glob)
174 *ProgrammingError: cannot strip from inside a transaction (glob)
175
175
176 $ hg oldanddeprecated
176 $ hg oldanddeprecated
177 devel-warn: foorbar is deprecated, go shopping
177 devel-warn: foorbar is deprecated, go shopping
178 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
178 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
179
179
180 #if no-chg
180 #if no-chg
181 $ hg oldanddeprecated --traceback
181 $ hg oldanddeprecated --traceback
182 devel-warn: foorbar is deprecated, go shopping
182 devel-warn: foorbar is deprecated, go shopping
183 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
183 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
184 */hg:* in <module> (glob) (?)
184 */hg:* in <module> (glob) (?)
185 */mercurial/dispatch.py:* in run (glob)
185 */mercurial/dispatch.py:* in run (glob)
186 */mercurial/dispatch.py:* in dispatch (glob)
186 */mercurial/dispatch.py:* in dispatch (glob)
187 */mercurial/dispatch.py:* in _runcatch (glob)
187 */mercurial/dispatch.py:* in _runcatch (glob)
188 */mercurial/dispatch.py:* in _callcatch (glob)
188 */mercurial/dispatch.py:* in _callcatch (glob)
189 */mercurial/scmutil.py* in callcatch (glob)
189 */mercurial/scmutil.py* in callcatch (glob)
190 */mercurial/dispatch.py:* in _runcatchfunc (glob)
190 */mercurial/dispatch.py:* in _runcatchfunc (glob)
191 */mercurial/dispatch.py:* in _dispatch (glob)
191 */mercurial/dispatch.py:* in _dispatch (glob)
192 */mercurial/dispatch.py:* in runcommand (glob)
192 */mercurial/dispatch.py:* in runcommand (glob)
193 */mercurial/dispatch.py:* in _runcommand (glob)
193 */mercurial/dispatch.py:* in _runcommand (glob)
194 */mercurial/dispatch.py:* in <lambda> (glob)
194 */mercurial/dispatch.py:* in <lambda> (glob)
195 */mercurial/util.py:* in check (glob)
195 */mercurial/util.py:* in check (glob)
196 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
196 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
197 #else
197 #else
198 $ hg oldanddeprecated --traceback
198 $ hg oldanddeprecated --traceback
199 devel-warn: foorbar is deprecated, go shopping
199 devel-warn: foorbar is deprecated, go shopping
200 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
200 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
201 */hg:* in <module> (glob)
201 */hg:* in <module> (glob)
202 */mercurial/dispatch.py:* in run (glob)
202 */mercurial/dispatch.py:* in run (glob)
203 */mercurial/dispatch.py:* in dispatch (glob)
203 */mercurial/dispatch.py:* in dispatch (glob)
204 */mercurial/dispatch.py:* in _runcatch (glob)
204 */mercurial/dispatch.py:* in _runcatch (glob)
205 */mercurial/dispatch.py:* in _callcatch (glob)
205 */mercurial/dispatch.py:* in _callcatch (glob)
206 */mercurial/scmutil.py:* in callcatch (glob)
206 */mercurial/scmutil.py:* in callcatch (glob)
207 */mercurial/dispatch.py:* in _runcatchfunc (glob)
207 */mercurial/dispatch.py:* in _runcatchfunc (glob)
208 */mercurial/dispatch.py:* in _dispatch (glob)
208 */mercurial/dispatch.py:* in _dispatch (glob)
209 */mercurial/dispatch.py:* in runcommand (glob)
209 */mercurial/dispatch.py:* in runcommand (glob)
210 */mercurial/dispatch.py:* in _runcommand (glob)
210 */mercurial/dispatch.py:* in _runcommand (glob)
211 */mercurial/dispatch.py:* in <lambda> (glob)
211 */mercurial/dispatch.py:* in <lambda> (glob)
212 */mercurial/util.py:* in check (glob)
212 */mercurial/util.py:* in check (glob)
213 */mercurial/commands.py:* in serve (glob)
213 */mercurial/commands.py:* in serve (glob)
214 */mercurial/server.py:* in runservice (glob)
214 */mercurial/server.py:* in runservice (glob)
215 */mercurial/commandserver.py:* in run (glob)
215 */mercurial/commandserver.py:* in run (glob)
216 */mercurial/commandserver.py:* in _mainloop (glob)
216 */mercurial/commandserver.py:* in _mainloop (glob)
217 */mercurial/commandserver.py:* in _acceptnewconnection (glob)
217 */mercurial/commandserver.py:* in _acceptnewconnection (glob)
218 */mercurial/commandserver.py:* in _runworker (glob)
218 */mercurial/commandserver.py:* in _runworker (glob)
219 */mercurial/commandserver.py:* in _serverequest (glob)
219 */mercurial/commandserver.py:* in _serverequest (glob)
220 */mercurial/commandserver.py:* in serve (glob)
220 */mercurial/commandserver.py:* in serve (glob)
221 */mercurial/commandserver.py:* in serveone (glob)
221 */mercurial/commandserver.py:* in serveone (glob)
222 */mercurial/chgserver.py:* in runcommand (glob)
222 */mercurial/chgserver.py:* in runcommand (glob)
223 */mercurial/commandserver.py:* in runcommand (glob)
223 */mercurial/commandserver.py:* in runcommand (glob)
224 */mercurial/commandserver.py:* in _dispatchcommand (glob)
224 */mercurial/commandserver.py:* in _dispatchcommand (glob)
225 */mercurial/dispatch.py:* in dispatch (glob)
225 */mercurial/dispatch.py:* in dispatch (glob)
226 */mercurial/dispatch.py:* in _runcatch (glob)
226 */mercurial/dispatch.py:* in _runcatch (glob)
227 */mercurial/dispatch.py:* in _callcatch (glob)
227 */mercurial/dispatch.py:* in _callcatch (glob)
228 */mercurial/scmutil.py:* in callcatch (glob)
228 */mercurial/scmutil.py:* in callcatch (glob)
229 */mercurial/dispatch.py:* in _runcatchfunc (glob)
229 */mercurial/dispatch.py:* in _runcatchfunc (glob)
230 */mercurial/dispatch.py:* in _dispatch (glob)
230 */mercurial/dispatch.py:* in _dispatch (glob)
231 */mercurial/dispatch.py:* in runcommand (glob)
231 */mercurial/dispatch.py:* in runcommand (glob)
232 */mercurial/dispatch.py:* in _runcommand (glob)
232 */mercurial/dispatch.py:* in _runcommand (glob)
233 */mercurial/dispatch.py:* in <lambda> (glob)
233 */mercurial/dispatch.py:* in <lambda> (glob)
234 */mercurial/util.py:* in check (glob)
234 */mercurial/util.py:* in check (glob)
235 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
235 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
236 #endif
236 #endif
237
237
238 #if no-chg
238 #if no-chg
239 $ hg blackbox -l 7
239 $ hg blackbox -l 7
240 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
240 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
241 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
241 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
242 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
242 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
243 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
243 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
244 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
244 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
245 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
245 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
246 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
246 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
247 */hg:* in <module> (glob) (?)
247 */hg:* in <module> (glob) (?)
248 */mercurial/dispatch.py:* in run (glob)
248 */mercurial/dispatch.py:* in run (glob)
249 */mercurial/dispatch.py:* in dispatch (glob)
249 */mercurial/dispatch.py:* in dispatch (glob)
250 */mercurial/dispatch.py:* in _runcatch (glob)
250 */mercurial/dispatch.py:* in _runcatch (glob)
251 */mercurial/dispatch.py:* in _callcatch (glob)
251 */mercurial/dispatch.py:* in _callcatch (glob)
252 */mercurial/scmutil.py* in callcatch (glob)
252 */mercurial/scmutil.py* in callcatch (glob)
253 */mercurial/dispatch.py:* in _runcatchfunc (glob)
253 */mercurial/dispatch.py:* in _runcatchfunc (glob)
254 */mercurial/dispatch.py:* in _dispatch (glob)
254 */mercurial/dispatch.py:* in _dispatch (glob)
255 */mercurial/dispatch.py:* in runcommand (glob)
255 */mercurial/dispatch.py:* in runcommand (glob)
256 */mercurial/dispatch.py:* in _runcommand (glob)
256 */mercurial/dispatch.py:* in _runcommand (glob)
257 */mercurial/dispatch.py:* in <lambda> (glob)
257 */mercurial/dispatch.py:* in <lambda> (glob)
258 */mercurial/util.py:* in check (glob)
258 */mercurial/util.py:* in check (glob)
259 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
259 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
260 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
260 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
261 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
261 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
262 #else
262 #else
263 $ hg blackbox -l 7
263 $ hg blackbox -l 7
264 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
264 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
265 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
265 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
266 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
266 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
267 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
267 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
268 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
268 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
269 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
269 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
270 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
270 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
271 */hg:* in <module> (glob)
271 */hg:* in <module> (glob)
272 */mercurial/dispatch.py:* in run (glob)
272 */mercurial/dispatch.py:* in run (glob)
273 */mercurial/dispatch.py:* in dispatch (glob)
273 */mercurial/dispatch.py:* in dispatch (glob)
274 */mercurial/dispatch.py:* in _runcatch (glob)
274 */mercurial/dispatch.py:* in _runcatch (glob)
275 */mercurial/dispatch.py:* in _callcatch (glob)
275 */mercurial/dispatch.py:* in _callcatch (glob)
276 */mercurial/scmutil.py:* in callcatch (glob)
276 */mercurial/scmutil.py:* in callcatch (glob)
277 */mercurial/dispatch.py:* in _runcatchfunc (glob)
277 */mercurial/dispatch.py:* in _runcatchfunc (glob)
278 */mercurial/dispatch.py:* in _dispatch (glob)
278 */mercurial/dispatch.py:* in _dispatch (glob)
279 */mercurial/dispatch.py:* in runcommand (glob)
279 */mercurial/dispatch.py:* in runcommand (glob)
280 */mercurial/dispatch.py:* in _runcommand (glob)
280 */mercurial/dispatch.py:* in _runcommand (glob)
281 */mercurial/dispatch.py:* in <lambda> (glob)
281 */mercurial/dispatch.py:* in <lambda> (glob)
282 */mercurial/util.py:* in check (glob)
282 */mercurial/util.py:* in check (glob)
283 */mercurial/commands.py:* in serve (glob)
283 */mercurial/commands.py:* in serve (glob)
284 */mercurial/server.py:* in runservice (glob)
284 */mercurial/server.py:* in runservice (glob)
285 */mercurial/commandserver.py:* in run (glob)
285 */mercurial/commandserver.py:* in run (glob)
286 */mercurial/commandserver.py:* in _mainloop (glob)
286 */mercurial/commandserver.py:* in _mainloop (glob)
287 */mercurial/commandserver.py:* in _acceptnewconnection (glob)
287 */mercurial/commandserver.py:* in _acceptnewconnection (glob)
288 */mercurial/commandserver.py:* in _runworker (glob)
288 */mercurial/commandserver.py:* in _runworker (glob)
289 */mercurial/commandserver.py:* in _serverequest (glob)
289 */mercurial/commandserver.py:* in _serverequest (glob)
290 */mercurial/commandserver.py:* in serve (glob)
290 */mercurial/commandserver.py:* in serve (glob)
291 */mercurial/commandserver.py:* in serveone (glob)
291 */mercurial/commandserver.py:* in serveone (glob)
292 */mercurial/chgserver.py:* in runcommand (glob)
292 */mercurial/chgserver.py:* in runcommand (glob)
293 */mercurial/commandserver.py:* in runcommand (glob)
293 */mercurial/commandserver.py:* in runcommand (glob)
294 */mercurial/commandserver.py:* in _dispatchcommand (glob)
294 */mercurial/commandserver.py:* in _dispatchcommand (glob)
295 */mercurial/dispatch.py:* in dispatch (glob)
295 */mercurial/dispatch.py:* in dispatch (glob)
296 */mercurial/dispatch.py:* in _runcatch (glob)
296 */mercurial/dispatch.py:* in _runcatch (glob)
297 */mercurial/dispatch.py:* in _callcatch (glob)
297 */mercurial/dispatch.py:* in _callcatch (glob)
298 */mercurial/scmutil.py:* in callcatch (glob)
298 */mercurial/scmutil.py:* in callcatch (glob)
299 */mercurial/dispatch.py:* in _runcatchfunc (glob)
299 */mercurial/dispatch.py:* in _runcatchfunc (glob)
300 */mercurial/dispatch.py:* in _dispatch (glob)
300 */mercurial/dispatch.py:* in _dispatch (glob)
301 */mercurial/dispatch.py:* in runcommand (glob)
301 */mercurial/dispatch.py:* in runcommand (glob)
302 */mercurial/dispatch.py:* in _runcommand (glob)
302 */mercurial/dispatch.py:* in _runcommand (glob)
303 */mercurial/dispatch.py:* in <lambda> (glob)
303 */mercurial/dispatch.py:* in <lambda> (glob)
304 */mercurial/util.py:* in check (glob)
304 */mercurial/util.py:* in check (glob)
305 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
305 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
306 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
306 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
307 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
307 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 7
308 #endif
308 #endif
309
309
310 Test programming error failure:
310 Test programming error failure:
311
311
312 $ hg buggytransaction 2>&1 | egrep -v '^ '
312 $ hg buggytransaction 2>&1 | egrep -v '^ '
313 ** Unknown exception encountered with possibly-broken third-party extension buggylocking
313 ** Unknown exception encountered with possibly-broken third-party extension buggylocking (version N/A)
314 ** which supports versions unknown of Mercurial.
314 ** which supports versions unknown of Mercurial.
315 ** Please disable buggylocking and try your action again.
315 ** Please disable buggylocking and try your action again.
316 ** If that fixes the bug please report it to the extension author.
316 ** If that fixes the bug please report it to the extension author.
317 ** Python * (glob)
317 ** Python * (glob)
318 ** Mercurial Distributed SCM (*) (glob)
318 ** Mercurial Distributed SCM (*) (glob)
319 ** Extensions loaded: * (glob)
319 ** Extensions loaded: * (glob)
320 ** ProgrammingError: transaction requires locking
320 ** ProgrammingError: transaction requires locking
321 Traceback (most recent call last):
321 Traceback (most recent call last):
322 *ProgrammingError: transaction requires locking (glob)
322 *ProgrammingError: transaction requires locking (glob)
323
323
324 $ hg programmingerror 2>&1 | egrep -v '^ '
324 $ hg programmingerror 2>&1 | egrep -v '^ '
325 ** Unknown exception encountered with possibly-broken third-party extension buggylocking
325 ** Unknown exception encountered with possibly-broken third-party extension buggylocking (version N/A)
326 ** which supports versions unknown of Mercurial.
326 ** which supports versions unknown of Mercurial.
327 ** Please disable buggylocking and try your action again.
327 ** Please disable buggylocking and try your action again.
328 ** If that fixes the bug please report it to the extension author.
328 ** If that fixes the bug please report it to the extension author.
329 ** Python * (glob)
329 ** Python * (glob)
330 ** Mercurial Distributed SCM (*) (glob)
330 ** Mercurial Distributed SCM (*) (glob)
331 ** Extensions loaded: * (glob)
331 ** Extensions loaded: * (glob)
332 ** ProgrammingError: something went wrong
332 ** ProgrammingError: something went wrong
333 ** (try again)
333 ** (try again)
334 Traceback (most recent call last):
334 Traceback (most recent call last):
335 *ProgrammingError: something went wrong (glob)
335 *ProgrammingError: something went wrong (glob)
336
336
337 Old style deprecation warning
337 Old style deprecation warning
338
338
339 $ hg nouiwarning
339 $ hg nouiwarning
340 $TESTTMP/buggylocking.py:*: DeprecationWarning: this is a test (glob)
340 $TESTTMP/buggylocking.py:*: DeprecationWarning: this is a test (glob)
341 (compatibility will be dropped after Mercurial-13.37, update your code.)
341 (compatibility will be dropped after Mercurial-13.37, update your code.)
342 util.nouideprecwarn(b'this is a test', b'13.37')
342 util.nouideprecwarn(b'this is a test', b'13.37')
343
343
344 (disabled outside of test run)
344 (disabled outside of test run)
345
345
346 $ HGEMITWARNINGS= hg nouiwarning
346 $ HGEMITWARNINGS= hg nouiwarning
347
347
348 Test warning on config option access and registration
348 Test warning on config option access and registration
349
349
350 $ cat << EOF > ${TESTTMP}/buggyconfig.py
350 $ cat << EOF > ${TESTTMP}/buggyconfig.py
351 > """A small extension that tests our developer warnings for config"""
351 > """A small extension that tests our developer warnings for config"""
352 >
352 >
353 > from mercurial import configitems, registrar
353 > from mercurial import configitems, registrar
354 >
354 >
355 > cmdtable = {}
355 > cmdtable = {}
356 > command = registrar.command(cmdtable)
356 > command = registrar.command(cmdtable)
357 >
357 >
358 > configtable = {}
358 > configtable = {}
359 > configitem = registrar.configitem(configtable)
359 > configitem = registrar.configitem(configtable)
360 >
360 >
361 > configitem(b'test', b'some', default=b'foo')
361 > configitem(b'test', b'some', default=b'foo')
362 > configitem(b'test', b'dynamic', default=configitems.dynamicdefault)
362 > configitem(b'test', b'dynamic', default=configitems.dynamicdefault)
363 > configitem(b'test', b'callable', default=list)
363 > configitem(b'test', b'callable', default=list)
364 > # overwrite a core config
364 > # overwrite a core config
365 > configitem(b'ui', b'quiet', default=False)
365 > configitem(b'ui', b'quiet', default=False)
366 > configitem(b'ui', b'interactive', default=None)
366 > configitem(b'ui', b'interactive', default=None)
367 >
367 >
368 > @command(b'buggyconfig')
368 > @command(b'buggyconfig')
369 > def cmdbuggyconfig(ui, repo):
369 > def cmdbuggyconfig(ui, repo):
370 > repo.ui.config(b'ui', b'quiet', True)
370 > repo.ui.config(b'ui', b'quiet', True)
371 > repo.ui.config(b'ui', b'interactive', False)
371 > repo.ui.config(b'ui', b'interactive', False)
372 > repo.ui.config(b'test', b'some', b'bar')
372 > repo.ui.config(b'test', b'some', b'bar')
373 > repo.ui.config(b'test', b'some', b'foo')
373 > repo.ui.config(b'test', b'some', b'foo')
374 > repo.ui.config(b'test', b'dynamic', b'some-required-default')
374 > repo.ui.config(b'test', b'dynamic', b'some-required-default')
375 > repo.ui.config(b'test', b'dynamic')
375 > repo.ui.config(b'test', b'dynamic')
376 > repo.ui.config(b'test', b'callable', [])
376 > repo.ui.config(b'test', b'callable', [])
377 > repo.ui.config(b'test', b'callable', b'foo')
377 > repo.ui.config(b'test', b'callable', b'foo')
378 > repo.ui.config(b'test', b'unregistered')
378 > repo.ui.config(b'test', b'unregistered')
379 > repo.ui.config(b'unregistered', b'unregistered')
379 > repo.ui.config(b'unregistered', b'unregistered')
380 > EOF
380 > EOF
381
381
382 $ hg --config "extensions.buggyconfig=${TESTTMP}/buggyconfig.py" buggyconfig
382 $ hg --config "extensions.buggyconfig=${TESTTMP}/buggyconfig.py" buggyconfig
383 devel-warn: extension 'buggyconfig' overwrite config item 'ui.interactive' at: */mercurial/extensions.py:* (_loadextra) (glob)
383 devel-warn: extension 'buggyconfig' overwrite config item 'ui.interactive' at: */mercurial/extensions.py:* (_loadextra) (glob)
384 devel-warn: extension 'buggyconfig' overwrite config item 'ui.quiet' at: */mercurial/extensions.py:* (_loadextra) (glob)
384 devel-warn: extension 'buggyconfig' overwrite config item 'ui.quiet' at: */mercurial/extensions.py:* (_loadextra) (glob)
385 devel-warn: specifying a mismatched default value for a registered config item: 'ui.quiet' 'True' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
385 devel-warn: specifying a mismatched default value for a registered config item: 'ui.quiet' 'True' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
386 devel-warn: specifying a mismatched default value for a registered config item: 'ui.interactive' 'False' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
386 devel-warn: specifying a mismatched default value for a registered config item: 'ui.interactive' 'False' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
387 devel-warn: specifying a mismatched default value for a registered config item: 'test.some' 'bar' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
387 devel-warn: specifying a mismatched default value for a registered config item: 'test.some' 'bar' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
388 devel-warn: config item requires an explicit default value: 'test.dynamic' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
388 devel-warn: config item requires an explicit default value: 'test.dynamic' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
389 devel-warn: specifying a mismatched default value for a registered config item: 'test.callable' 'foo' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
389 devel-warn: specifying a mismatched default value for a registered config item: 'test.callable' 'foo' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
390 devel-warn: accessing unregistered config item: 'test.unregistered' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
390 devel-warn: accessing unregistered config item: 'test.unregistered' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
391 devel-warn: accessing unregistered config item: 'unregistered.unregistered' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
391 devel-warn: accessing unregistered config item: 'unregistered.unregistered' at: $TESTTMP/buggyconfig.py:* (cmdbuggyconfig) (glob)
392
392
393 $ cd ..
393 $ cd ..
@@ -1,1891 +1,1891 b''
1 Test basic extension support
1 Test basic extension support
2 $ cat > unflush.py <<EOF
2 $ cat > unflush.py <<EOF
3 > import sys
3 > import sys
4 > from mercurial import pycompat
4 > from mercurial import pycompat
5 > if pycompat.ispy3:
5 > if pycompat.ispy3:
6 > # no changes required
6 > # no changes required
7 > sys.exit(0)
7 > sys.exit(0)
8 > with open(sys.argv[1], 'rb') as f:
8 > with open(sys.argv[1], 'rb') as f:
9 > data = f.read()
9 > data = f.read()
10 > with open(sys.argv[1], 'wb') as f:
10 > with open(sys.argv[1], 'wb') as f:
11 > f.write(data.replace(b', flush=True', b''))
11 > f.write(data.replace(b', flush=True', b''))
12 > EOF
12 > EOF
13
13
14 $ cat > foobar.py <<EOF
14 $ cat > foobar.py <<EOF
15 > import os
15 > import os
16 > from mercurial import commands, exthelper, registrar
16 > from mercurial import commands, exthelper, registrar
17 >
17 >
18 > eh = exthelper.exthelper()
18 > eh = exthelper.exthelper()
19 > eh.configitem(b'tests', b'foo', default=b"Foo")
19 > eh.configitem(b'tests', b'foo', default=b"Foo")
20 >
20 >
21 > uisetup = eh.finaluisetup
21 > uisetup = eh.finaluisetup
22 > uipopulate = eh.finaluipopulate
22 > uipopulate = eh.finaluipopulate
23 > reposetup = eh.finalreposetup
23 > reposetup = eh.finalreposetup
24 > cmdtable = eh.cmdtable
24 > cmdtable = eh.cmdtable
25 > configtable = eh.configtable
25 > configtable = eh.configtable
26 >
26 >
27 > @eh.uisetup
27 > @eh.uisetup
28 > def _uisetup(ui):
28 > def _uisetup(ui):
29 > ui.debug(b"uisetup called [debug]\\n")
29 > ui.debug(b"uisetup called [debug]\\n")
30 > ui.write(b"uisetup called\\n")
30 > ui.write(b"uisetup called\\n")
31 > ui.status(b"uisetup called [status]\\n")
31 > ui.status(b"uisetup called [status]\\n")
32 > ui.flush()
32 > ui.flush()
33 > @eh.uipopulate
33 > @eh.uipopulate
34 > def _uipopulate(ui):
34 > def _uipopulate(ui):
35 > ui._populatecnt = getattr(ui, "_populatecnt", 0) + 1
35 > ui._populatecnt = getattr(ui, "_populatecnt", 0) + 1
36 > ui.write(b"uipopulate called (%d times)\n" % ui._populatecnt)
36 > ui.write(b"uipopulate called (%d times)\n" % ui._populatecnt)
37 > @eh.reposetup
37 > @eh.reposetup
38 > def _reposetup(ui, repo):
38 > def _reposetup(ui, repo):
39 > ui.write(b"reposetup called for %s\\n" % os.path.basename(repo.root))
39 > ui.write(b"reposetup called for %s\\n" % os.path.basename(repo.root))
40 > ui.write(b"ui %s= repo.ui\\n" % (ui == repo.ui and b"=" or b"!"))
40 > ui.write(b"ui %s= repo.ui\\n" % (ui == repo.ui and b"=" or b"!"))
41 > ui.flush()
41 > ui.flush()
42 > @eh.command(b'foo', [], b'hg foo')
42 > @eh.command(b'foo', [], b'hg foo')
43 > def foo(ui, *args, **kwargs):
43 > def foo(ui, *args, **kwargs):
44 > foo = ui.config(b'tests', b'foo')
44 > foo = ui.config(b'tests', b'foo')
45 > ui.write(foo)
45 > ui.write(foo)
46 > ui.write(b"\\n")
46 > ui.write(b"\\n")
47 > @eh.command(b'bar', [], b'hg bar', norepo=True)
47 > @eh.command(b'bar', [], b'hg bar', norepo=True)
48 > def bar(ui, *args, **kwargs):
48 > def bar(ui, *args, **kwargs):
49 > ui.write(b"Bar\\n")
49 > ui.write(b"Bar\\n")
50 > EOF
50 > EOF
51 $ abspath=`pwd`/foobar.py
51 $ abspath=`pwd`/foobar.py
52
52
53 $ mkdir barfoo
53 $ mkdir barfoo
54 $ cp foobar.py barfoo/__init__.py
54 $ cp foobar.py barfoo/__init__.py
55 $ barfoopath=`pwd`/barfoo
55 $ barfoopath=`pwd`/barfoo
56
56
57 $ hg init a
57 $ hg init a
58 $ cd a
58 $ cd a
59 $ echo foo > file
59 $ echo foo > file
60 $ hg add file
60 $ hg add file
61 $ hg commit -m 'add file'
61 $ hg commit -m 'add file'
62
62
63 $ echo '[extensions]' >> $HGRCPATH
63 $ echo '[extensions]' >> $HGRCPATH
64 $ echo "foobar = $abspath" >> $HGRCPATH
64 $ echo "foobar = $abspath" >> $HGRCPATH
65 $ hg foo
65 $ hg foo
66 uisetup called
66 uisetup called
67 uisetup called [status]
67 uisetup called [status]
68 uipopulate called (1 times)
68 uipopulate called (1 times)
69 uipopulate called (1 times)
69 uipopulate called (1 times)
70 uipopulate called (1 times)
70 uipopulate called (1 times)
71 reposetup called for a
71 reposetup called for a
72 ui == repo.ui
72 ui == repo.ui
73 uipopulate called (1 times) (chg !)
73 uipopulate called (1 times) (chg !)
74 uipopulate called (1 times) (chg !)
74 uipopulate called (1 times) (chg !)
75 uipopulate called (1 times) (chg !)
75 uipopulate called (1 times) (chg !)
76 uipopulate called (1 times) (chg !)
76 uipopulate called (1 times) (chg !)
77 uipopulate called (1 times) (chg !)
77 uipopulate called (1 times) (chg !)
78 reposetup called for a (chg !)
78 reposetup called for a (chg !)
79 ui == repo.ui (chg !)
79 ui == repo.ui (chg !)
80 Foo
80 Foo
81 $ hg foo --quiet
81 $ hg foo --quiet
82 uisetup called (no-chg !)
82 uisetup called (no-chg !)
83 uipopulate called (1 times)
83 uipopulate called (1 times)
84 uipopulate called (1 times)
84 uipopulate called (1 times)
85 uipopulate called (1 times) (chg !)
85 uipopulate called (1 times) (chg !)
86 uipopulate called (1 times) (chg !)
86 uipopulate called (1 times) (chg !)
87 uipopulate called (1 times)
87 uipopulate called (1 times)
88 reposetup called for a
88 reposetup called for a
89 ui == repo.ui
89 ui == repo.ui
90 Foo
90 Foo
91 $ hg foo --debug
91 $ hg foo --debug
92 uisetup called [debug] (no-chg !)
92 uisetup called [debug] (no-chg !)
93 uisetup called (no-chg !)
93 uisetup called (no-chg !)
94 uisetup called [status] (no-chg !)
94 uisetup called [status] (no-chg !)
95 uipopulate called (1 times)
95 uipopulate called (1 times)
96 uipopulate called (1 times)
96 uipopulate called (1 times)
97 uipopulate called (1 times) (chg !)
97 uipopulate called (1 times) (chg !)
98 uipopulate called (1 times) (chg !)
98 uipopulate called (1 times) (chg !)
99 uipopulate called (1 times)
99 uipopulate called (1 times)
100 reposetup called for a
100 reposetup called for a
101 ui == repo.ui
101 ui == repo.ui
102 Foo
102 Foo
103
103
104 $ cd ..
104 $ cd ..
105 $ hg clone a b
105 $ hg clone a b
106 uisetup called (no-chg !)
106 uisetup called (no-chg !)
107 uisetup called [status] (no-chg !)
107 uisetup called [status] (no-chg !)
108 uipopulate called (1 times)
108 uipopulate called (1 times)
109 uipopulate called (1 times) (chg !)
109 uipopulate called (1 times) (chg !)
110 uipopulate called (1 times)
110 uipopulate called (1 times)
111 reposetup called for a
111 reposetup called for a
112 ui == repo.ui
112 ui == repo.ui
113 uipopulate called (1 times)
113 uipopulate called (1 times)
114 reposetup called for b
114 reposetup called for b
115 ui == repo.ui
115 ui == repo.ui
116 updating to branch default
116 updating to branch default
117 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
118
118
119 $ hg bar
119 $ hg bar
120 uisetup called (no-chg !)
120 uisetup called (no-chg !)
121 uisetup called [status] (no-chg !)
121 uisetup called [status] (no-chg !)
122 uipopulate called (1 times)
122 uipopulate called (1 times)
123 uipopulate called (1 times) (chg !)
123 uipopulate called (1 times) (chg !)
124 Bar
124 Bar
125 $ echo 'foobar = !' >> $HGRCPATH
125 $ echo 'foobar = !' >> $HGRCPATH
126
126
127 module/__init__.py-style
127 module/__init__.py-style
128
128
129 $ echo "barfoo = $barfoopath" >> $HGRCPATH
129 $ echo "barfoo = $barfoopath" >> $HGRCPATH
130 $ cd a
130 $ cd a
131 $ hg foo
131 $ hg foo
132 uisetup called
132 uisetup called
133 uisetup called [status]
133 uisetup called [status]
134 uipopulate called (1 times)
134 uipopulate called (1 times)
135 uipopulate called (1 times)
135 uipopulate called (1 times)
136 uipopulate called (1 times)
136 uipopulate called (1 times)
137 reposetup called for a
137 reposetup called for a
138 ui == repo.ui
138 ui == repo.ui
139 uipopulate called (1 times) (chg !)
139 uipopulate called (1 times) (chg !)
140 uipopulate called (1 times) (chg !)
140 uipopulate called (1 times) (chg !)
141 uipopulate called (1 times) (chg !)
141 uipopulate called (1 times) (chg !)
142 uipopulate called (1 times) (chg !)
142 uipopulate called (1 times) (chg !)
143 uipopulate called (1 times) (chg !)
143 uipopulate called (1 times) (chg !)
144 reposetup called for a (chg !)
144 reposetup called for a (chg !)
145 ui == repo.ui (chg !)
145 ui == repo.ui (chg !)
146 Foo
146 Foo
147 $ echo 'barfoo = !' >> $HGRCPATH
147 $ echo 'barfoo = !' >> $HGRCPATH
148
148
149 Check that extensions are loaded in phases:
149 Check that extensions are loaded in phases:
150
150
151 $ cat > foo.py <<EOF
151 $ cat > foo.py <<EOF
152 > from __future__ import print_function
152 > from __future__ import print_function
153 > import os
153 > import os
154 > from mercurial import exthelper
154 > from mercurial import exthelper
155 > from mercurial.utils import procutil
155 > from mercurial.utils import procutil
156 >
156 >
157 > write = procutil.stdout.write
157 > write = procutil.stdout.write
158 > name = os.path.basename(__file__).rsplit('.', 1)[0]
158 > name = os.path.basename(__file__).rsplit('.', 1)[0]
159 > bytesname = name.encode('utf-8')
159 > bytesname = name.encode('utf-8')
160 > write(b"1) %s imported\n" % bytesname)
160 > write(b"1) %s imported\n" % bytesname)
161 > eh = exthelper.exthelper()
161 > eh = exthelper.exthelper()
162 > @eh.uisetup
162 > @eh.uisetup
163 > def _uisetup(ui):
163 > def _uisetup(ui):
164 > write(b"2) %s uisetup\n" % bytesname)
164 > write(b"2) %s uisetup\n" % bytesname)
165 > @eh.extsetup
165 > @eh.extsetup
166 > def _extsetup(ui):
166 > def _extsetup(ui):
167 > write(b"3) %s extsetup\n" % bytesname)
167 > write(b"3) %s extsetup\n" % bytesname)
168 > @eh.uipopulate
168 > @eh.uipopulate
169 > def _uipopulate(ui):
169 > def _uipopulate(ui):
170 > write(b"4) %s uipopulate\n" % bytesname)
170 > write(b"4) %s uipopulate\n" % bytesname)
171 > @eh.reposetup
171 > @eh.reposetup
172 > def _reposetup(ui, repo):
172 > def _reposetup(ui, repo):
173 > write(b"5) %s reposetup\n" % bytesname)
173 > write(b"5) %s reposetup\n" % bytesname)
174 >
174 >
175 > extsetup = eh.finalextsetup
175 > extsetup = eh.finalextsetup
176 > reposetup = eh.finalreposetup
176 > reposetup = eh.finalreposetup
177 > uipopulate = eh.finaluipopulate
177 > uipopulate = eh.finaluipopulate
178 > uisetup = eh.finaluisetup
178 > uisetup = eh.finaluisetup
179 > revsetpredicate = eh.revsetpredicate
179 > revsetpredicate = eh.revsetpredicate
180 >
180 >
181 > # custom predicate to check registration of functions at loading
181 > # custom predicate to check registration of functions at loading
182 > from mercurial import (
182 > from mercurial import (
183 > smartset,
183 > smartset,
184 > )
184 > )
185 > @eh.revsetpredicate(bytesname, safe=True) # safe=True for query via hgweb
185 > @eh.revsetpredicate(bytesname, safe=True) # safe=True for query via hgweb
186 > def custompredicate(repo, subset, x):
186 > def custompredicate(repo, subset, x):
187 > return smartset.baseset([r for r in subset if r in {0}])
187 > return smartset.baseset([r for r in subset if r in {0}])
188 > EOF
188 > EOF
189 $ "$PYTHON" $TESTTMP/unflush.py foo.py
189 $ "$PYTHON" $TESTTMP/unflush.py foo.py
190
190
191 $ cp foo.py bar.py
191 $ cp foo.py bar.py
192 $ echo 'foo = foo.py' >> $HGRCPATH
192 $ echo 'foo = foo.py' >> $HGRCPATH
193 $ echo 'bar = bar.py' >> $HGRCPATH
193 $ echo 'bar = bar.py' >> $HGRCPATH
194
194
195 Check normal command's load order of extensions and registration of functions
195 Check normal command's load order of extensions and registration of functions
196
196
197 $ hg log -r "foo() and bar()" -q
197 $ hg log -r "foo() and bar()" -q
198 1) foo imported
198 1) foo imported
199 1) bar imported
199 1) bar imported
200 2) foo uisetup
200 2) foo uisetup
201 2) bar uisetup
201 2) bar uisetup
202 3) foo extsetup
202 3) foo extsetup
203 3) bar extsetup
203 3) bar extsetup
204 4) foo uipopulate
204 4) foo uipopulate
205 4) bar uipopulate
205 4) bar uipopulate
206 4) foo uipopulate
206 4) foo uipopulate
207 4) bar uipopulate
207 4) bar uipopulate
208 4) foo uipopulate
208 4) foo uipopulate
209 4) bar uipopulate
209 4) bar uipopulate
210 5) foo reposetup
210 5) foo reposetup
211 5) bar reposetup
211 5) bar reposetup
212 0:c24b9ac61126
212 0:c24b9ac61126
213
213
214 Check hgweb's load order of extensions and registration of functions
214 Check hgweb's load order of extensions and registration of functions
215
215
216 $ cat > hgweb.cgi <<EOF
216 $ cat > hgweb.cgi <<EOF
217 > #!$PYTHON
217 > #!$PYTHON
218 > from mercurial import demandimport; demandimport.enable()
218 > from mercurial import demandimport; demandimport.enable()
219 > from mercurial.hgweb import hgweb
219 > from mercurial.hgweb import hgweb
220 > from mercurial.hgweb import wsgicgi
220 > from mercurial.hgweb import wsgicgi
221 > application = hgweb(b'.', b'test repo')
221 > application = hgweb(b'.', b'test repo')
222 > wsgicgi.launch(application)
222 > wsgicgi.launch(application)
223 > EOF
223 > EOF
224 $ . "$TESTDIR/cgienv"
224 $ . "$TESTDIR/cgienv"
225
225
226 $ PATH_INFO='/' SCRIPT_NAME='' "$PYTHON" hgweb.cgi \
226 $ PATH_INFO='/' SCRIPT_NAME='' "$PYTHON" hgweb.cgi \
227 > | grep '^[0-9]) ' # ignores HTML output
227 > | grep '^[0-9]) ' # ignores HTML output
228 1) foo imported
228 1) foo imported
229 1) bar imported
229 1) bar imported
230 2) foo uisetup
230 2) foo uisetup
231 2) bar uisetup
231 2) bar uisetup
232 3) foo extsetup
232 3) foo extsetup
233 3) bar extsetup
233 3) bar extsetup
234 4) foo uipopulate
234 4) foo uipopulate
235 4) bar uipopulate
235 4) bar uipopulate
236 4) foo uipopulate
236 4) foo uipopulate
237 4) bar uipopulate
237 4) bar uipopulate
238 5) foo reposetup
238 5) foo reposetup
239 5) bar reposetup
239 5) bar reposetup
240
240
241 (check that revset predicate foo() and bar() are available)
241 (check that revset predicate foo() and bar() are available)
242
242
243 #if msys
243 #if msys
244 $ PATH_INFO='//shortlog'
244 $ PATH_INFO='//shortlog'
245 #else
245 #else
246 $ PATH_INFO='/shortlog'
246 $ PATH_INFO='/shortlog'
247 #endif
247 #endif
248 $ export PATH_INFO
248 $ export PATH_INFO
249 $ SCRIPT_NAME='' QUERY_STRING='rev=foo() and bar()' "$PYTHON" hgweb.cgi \
249 $ SCRIPT_NAME='' QUERY_STRING='rev=foo() and bar()' "$PYTHON" hgweb.cgi \
250 > | grep '<a href="/rev/[0-9a-z]*">'
250 > | grep '<a href="/rev/[0-9a-z]*">'
251 <a href="/rev/c24b9ac61126">add file</a>
251 <a href="/rev/c24b9ac61126">add file</a>
252
252
253 $ echo 'foo = !' >> $HGRCPATH
253 $ echo 'foo = !' >> $HGRCPATH
254 $ echo 'bar = !' >> $HGRCPATH
254 $ echo 'bar = !' >> $HGRCPATH
255
255
256 Check "from __future__ import absolute_import" support for external libraries
256 Check "from __future__ import absolute_import" support for external libraries
257
257
258 (import-checker.py reports issues for some of heredoc python code
258 (import-checker.py reports issues for some of heredoc python code
259 fragments below, because import-checker.py does not know test specific
259 fragments below, because import-checker.py does not know test specific
260 package hierarchy. NO_CHECK_* should be used as a limit mark of
260 package hierarchy. NO_CHECK_* should be used as a limit mark of
261 heredoc, in order to make import-checker.py ignore them. For
261 heredoc, in order to make import-checker.py ignore them. For
262 simplicity, all python code fragments below are generated with such
262 simplicity, all python code fragments below are generated with such
263 limit mark, regardless of importing module or not.)
263 limit mark, regardless of importing module or not.)
264
264
265 #if windows
265 #if windows
266 $ PATHSEP=";"
266 $ PATHSEP=";"
267 #else
267 #else
268 $ PATHSEP=":"
268 $ PATHSEP=":"
269 #endif
269 #endif
270 $ export PATHSEP
270 $ export PATHSEP
271
271
272 $ mkdir $TESTTMP/libroot
272 $ mkdir $TESTTMP/libroot
273 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
273 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
274 $ mkdir $TESTTMP/libroot/mod
274 $ mkdir $TESTTMP/libroot/mod
275 $ touch $TESTTMP/libroot/mod/__init__.py
275 $ touch $TESTTMP/libroot/mod/__init__.py
276 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
276 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
277
277
278 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<NO_CHECK_EOF
278 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<NO_CHECK_EOF
279 > from __future__ import absolute_import, print_function
279 > from __future__ import absolute_import, print_function
280 > import ambig # should load "libroot/ambig.py"
280 > import ambig # should load "libroot/ambig.py"
281 > s = ambig.s
281 > s = ambig.s
282 > NO_CHECK_EOF
282 > NO_CHECK_EOF
283 $ cat > loadabs.py <<NO_CHECK_EOF
283 $ cat > loadabs.py <<NO_CHECK_EOF
284 > import mod.ambigabs as ambigabs
284 > import mod.ambigabs as ambigabs
285 > def extsetup(ui):
285 > def extsetup(ui):
286 > print('ambigabs.s=%s' % ambigabs.s, flush=True)
286 > print('ambigabs.s=%s' % ambigabs.s, flush=True)
287 > NO_CHECK_EOF
287 > NO_CHECK_EOF
288 $ "$PYTHON" $TESTTMP/unflush.py loadabs.py
288 $ "$PYTHON" $TESTTMP/unflush.py loadabs.py
289 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
289 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
290 ambigabs.s=libroot/ambig.py
290 ambigabs.s=libroot/ambig.py
291 $TESTTMP/a
291 $TESTTMP/a
292
292
293 #if no-py3
293 #if no-py3
294 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<NO_CHECK_EOF
294 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<NO_CHECK_EOF
295 > from __future__ import print_function
295 > from __future__ import print_function
296 > import ambig # should load "libroot/mod/ambig.py"
296 > import ambig # should load "libroot/mod/ambig.py"
297 > s = ambig.s
297 > s = ambig.s
298 > NO_CHECK_EOF
298 > NO_CHECK_EOF
299 $ cat > loadrel.py <<NO_CHECK_EOF
299 $ cat > loadrel.py <<NO_CHECK_EOF
300 > import mod.ambigrel as ambigrel
300 > import mod.ambigrel as ambigrel
301 > def extsetup(ui):
301 > def extsetup(ui):
302 > print('ambigrel.s=%s' % ambigrel.s, flush=True)
302 > print('ambigrel.s=%s' % ambigrel.s, flush=True)
303 > NO_CHECK_EOF
303 > NO_CHECK_EOF
304 $ "$PYTHON" $TESTTMP/unflush.py loadrel.py
304 $ "$PYTHON" $TESTTMP/unflush.py loadrel.py
305 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
305 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
306 ambigrel.s=libroot/mod/ambig.py
306 ambigrel.s=libroot/mod/ambig.py
307 $TESTTMP/a
307 $TESTTMP/a
308 #endif
308 #endif
309
309
310 Check absolute/relative import of extension specific modules
310 Check absolute/relative import of extension specific modules
311
311
312 $ mkdir $TESTTMP/extroot
312 $ mkdir $TESTTMP/extroot
313 $ cat > $TESTTMP/extroot/bar.py <<NO_CHECK_EOF
313 $ cat > $TESTTMP/extroot/bar.py <<NO_CHECK_EOF
314 > s = b'this is extroot.bar'
314 > s = b'this is extroot.bar'
315 > NO_CHECK_EOF
315 > NO_CHECK_EOF
316 $ mkdir $TESTTMP/extroot/sub1
316 $ mkdir $TESTTMP/extroot/sub1
317 $ cat > $TESTTMP/extroot/sub1/__init__.py <<NO_CHECK_EOF
317 $ cat > $TESTTMP/extroot/sub1/__init__.py <<NO_CHECK_EOF
318 > s = b'this is extroot.sub1.__init__'
318 > s = b'this is extroot.sub1.__init__'
319 > NO_CHECK_EOF
319 > NO_CHECK_EOF
320 $ cat > $TESTTMP/extroot/sub1/baz.py <<NO_CHECK_EOF
320 $ cat > $TESTTMP/extroot/sub1/baz.py <<NO_CHECK_EOF
321 > s = b'this is extroot.sub1.baz'
321 > s = b'this is extroot.sub1.baz'
322 > NO_CHECK_EOF
322 > NO_CHECK_EOF
323 $ cat > $TESTTMP/extroot/__init__.py <<NO_CHECK_EOF
323 $ cat > $TESTTMP/extroot/__init__.py <<NO_CHECK_EOF
324 > from __future__ import absolute_import
324 > from __future__ import absolute_import
325 > s = b'this is extroot.__init__'
325 > s = b'this is extroot.__init__'
326 > from . import foo
326 > from . import foo
327 > def extsetup(ui):
327 > def extsetup(ui):
328 > ui.write(b'(extroot) ', foo.func(), b'\n')
328 > ui.write(b'(extroot) ', foo.func(), b'\n')
329 > ui.flush()
329 > ui.flush()
330 > NO_CHECK_EOF
330 > NO_CHECK_EOF
331
331
332 $ cat > $TESTTMP/extroot/foo.py <<NO_CHECK_EOF
332 $ cat > $TESTTMP/extroot/foo.py <<NO_CHECK_EOF
333 > # test absolute import
333 > # test absolute import
334 > buf = []
334 > buf = []
335 > def func():
335 > def func():
336 > # "not locals" case
336 > # "not locals" case
337 > import extroot.bar
337 > import extroot.bar
338 > buf.append(b'import extroot.bar in func(): %s' % extroot.bar.s)
338 > buf.append(b'import extroot.bar in func(): %s' % extroot.bar.s)
339 > return b'\n(extroot) '.join(buf)
339 > return b'\n(extroot) '.join(buf)
340 > # b"fromlist == ('*',)" case
340 > # b"fromlist == ('*',)" case
341 > from extroot.bar import *
341 > from extroot.bar import *
342 > buf.append(b'from extroot.bar import *: %s' % s)
342 > buf.append(b'from extroot.bar import *: %s' % s)
343 > # "not fromlist" and "if '.' in name" case
343 > # "not fromlist" and "if '.' in name" case
344 > import extroot.sub1.baz
344 > import extroot.sub1.baz
345 > buf.append(b'import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
345 > buf.append(b'import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
346 > # "not fromlist" and NOT "if '.' in name" case
346 > # "not fromlist" and NOT "if '.' in name" case
347 > import extroot
347 > import extroot
348 > buf.append(b'import extroot: %s' % extroot.s)
348 > buf.append(b'import extroot: %s' % extroot.s)
349 > # NOT "not fromlist" and NOT "level != -1" case
349 > # NOT "not fromlist" and NOT "level != -1" case
350 > from extroot.bar import s
350 > from extroot.bar import s
351 > buf.append(b'from extroot.bar import s: %s' % s)
351 > buf.append(b'from extroot.bar import s: %s' % s)
352 > NO_CHECK_EOF
352 > NO_CHECK_EOF
353 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
353 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
354 (extroot) from extroot.bar import *: this is extroot.bar
354 (extroot) from extroot.bar import *: this is extroot.bar
355 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
355 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
356 (extroot) import extroot: this is extroot.__init__
356 (extroot) import extroot: this is extroot.__init__
357 (extroot) from extroot.bar import s: this is extroot.bar
357 (extroot) from extroot.bar import s: this is extroot.bar
358 (extroot) import extroot.bar in func(): this is extroot.bar
358 (extroot) import extroot.bar in func(): this is extroot.bar
359 $TESTTMP/a
359 $TESTTMP/a
360
360
361 #if no-py3
361 #if no-py3
362 $ rm "$TESTTMP"/extroot/foo.*
362 $ rm "$TESTTMP"/extroot/foo.*
363 $ rm -Rf "$TESTTMP/extroot/__pycache__"
363 $ rm -Rf "$TESTTMP/extroot/__pycache__"
364 $ cat > $TESTTMP/extroot/foo.py <<NO_CHECK_EOF
364 $ cat > $TESTTMP/extroot/foo.py <<NO_CHECK_EOF
365 > # test relative import
365 > # test relative import
366 > buf = []
366 > buf = []
367 > def func():
367 > def func():
368 > # "not locals" case
368 > # "not locals" case
369 > import bar
369 > import bar
370 > buf.append('import bar in func(): %s' % bar.s)
370 > buf.append('import bar in func(): %s' % bar.s)
371 > return '\n(extroot) '.join(buf)
371 > return '\n(extroot) '.join(buf)
372 > # "fromlist == ('*',)" case
372 > # "fromlist == ('*',)" case
373 > from bar import *
373 > from bar import *
374 > buf.append('from bar import *: %s' % s)
374 > buf.append('from bar import *: %s' % s)
375 > # "not fromlist" and "if '.' in name" case
375 > # "not fromlist" and "if '.' in name" case
376 > import sub1.baz
376 > import sub1.baz
377 > buf.append('import sub1.baz: %s' % sub1.baz.s)
377 > buf.append('import sub1.baz: %s' % sub1.baz.s)
378 > # "not fromlist" and NOT "if '.' in name" case
378 > # "not fromlist" and NOT "if '.' in name" case
379 > import sub1
379 > import sub1
380 > buf.append('import sub1: %s' % sub1.s)
380 > buf.append('import sub1: %s' % sub1.s)
381 > # NOT "not fromlist" and NOT "level != -1" case
381 > # NOT "not fromlist" and NOT "level != -1" case
382 > from bar import s
382 > from bar import s
383 > buf.append('from bar import s: %s' % s)
383 > buf.append('from bar import s: %s' % s)
384 > NO_CHECK_EOF
384 > NO_CHECK_EOF
385 $ hg --config extensions.extroot=$TESTTMP/extroot root
385 $ hg --config extensions.extroot=$TESTTMP/extroot root
386 (extroot) from bar import *: this is extroot.bar
386 (extroot) from bar import *: this is extroot.bar
387 (extroot) import sub1.baz: this is extroot.sub1.baz
387 (extroot) import sub1.baz: this is extroot.sub1.baz
388 (extroot) import sub1: this is extroot.sub1.__init__
388 (extroot) import sub1: this is extroot.sub1.__init__
389 (extroot) from bar import s: this is extroot.bar
389 (extroot) from bar import s: this is extroot.bar
390 (extroot) import bar in func(): this is extroot.bar
390 (extroot) import bar in func(): this is extroot.bar
391 $TESTTMP/a
391 $TESTTMP/a
392 #endif
392 #endif
393
393
394 #if demandimport
394 #if demandimport
395
395
396 Examine whether module loading is delayed until actual referring, even
396 Examine whether module loading is delayed until actual referring, even
397 though module is imported with "absolute_import" feature.
397 though module is imported with "absolute_import" feature.
398
398
399 Files below in each packages are used for described purpose:
399 Files below in each packages are used for described purpose:
400
400
401 - "called": examine whether "from MODULE import ATTR" works correctly
401 - "called": examine whether "from MODULE import ATTR" works correctly
402 - "unused": examine whether loading is delayed correctly
402 - "unused": examine whether loading is delayed correctly
403 - "used": examine whether "from PACKAGE import MODULE" works correctly
403 - "used": examine whether "from PACKAGE import MODULE" works correctly
404
404
405 Package hierarchy is needed to examine whether demand importing works
405 Package hierarchy is needed to examine whether demand importing works
406 as expected for "from SUB.PACK.AGE import MODULE".
406 as expected for "from SUB.PACK.AGE import MODULE".
407
407
408 Setup "external library" to be imported with "absolute_import"
408 Setup "external library" to be imported with "absolute_import"
409 feature.
409 feature.
410
410
411 $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2
411 $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2
412 $ touch $TESTTMP/extlibroot/__init__.py
412 $ touch $TESTTMP/extlibroot/__init__.py
413 $ touch $TESTTMP/extlibroot/lsub1/__init__.py
413 $ touch $TESTTMP/extlibroot/lsub1/__init__.py
414 $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py
414 $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py
415
415
416 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<NO_CHECK_EOF
416 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<NO_CHECK_EOF
417 > def func():
417 > def func():
418 > return b"this is extlibroot.lsub1.lsub2.called.func()"
418 > return b"this is extlibroot.lsub1.lsub2.called.func()"
419 > NO_CHECK_EOF
419 > NO_CHECK_EOF
420 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<NO_CHECK_EOF
420 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<NO_CHECK_EOF
421 > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally")
421 > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally")
422 > NO_CHECK_EOF
422 > NO_CHECK_EOF
423 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<NO_CHECK_EOF
423 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<NO_CHECK_EOF
424 > detail = b"this is extlibroot.lsub1.lsub2.used"
424 > detail = b"this is extlibroot.lsub1.lsub2.used"
425 > NO_CHECK_EOF
425 > NO_CHECK_EOF
426
426
427 Setup sub-package of "external library", which causes instantiation of
427 Setup sub-package of "external library", which causes instantiation of
428 demandmod in "recurse down the module chain" code path. Relative
428 demandmod in "recurse down the module chain" code path. Relative
429 importing with "absolute_import" feature isn't tested, because "level
429 importing with "absolute_import" feature isn't tested, because "level
430 >=1 " doesn't cause instantiation of demandmod.
430 >=1 " doesn't cause instantiation of demandmod.
431
431
432 $ mkdir -p $TESTTMP/extlibroot/recursedown/abs
432 $ mkdir -p $TESTTMP/extlibroot/recursedown/abs
433 $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<NO_CHECK_EOF
433 $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<NO_CHECK_EOF
434 > detail = b"this is extlibroot.recursedown.abs.used"
434 > detail = b"this is extlibroot.recursedown.abs.used"
435 > NO_CHECK_EOF
435 > NO_CHECK_EOF
436 $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<NO_CHECK_EOF
436 $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<NO_CHECK_EOF
437 > from __future__ import absolute_import
437 > from __future__ import absolute_import
438 > from extlibroot.recursedown.abs.used import detail
438 > from extlibroot.recursedown.abs.used import detail
439 > NO_CHECK_EOF
439 > NO_CHECK_EOF
440
440
441 $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy
441 $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy
442 $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<NO_CHECK_EOF
442 $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<NO_CHECK_EOF
443 > detail = b"this is extlibroot.recursedown.legacy.used"
443 > detail = b"this is extlibroot.recursedown.legacy.used"
444 > NO_CHECK_EOF
444 > NO_CHECK_EOF
445 $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<NO_CHECK_EOF
445 $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<NO_CHECK_EOF
446 > # legacy style (level == -1) import
446 > # legacy style (level == -1) import
447 > from extlibroot.recursedown.legacy.used import detail
447 > from extlibroot.recursedown.legacy.used import detail
448 > NO_CHECK_EOF
448 > NO_CHECK_EOF
449
449
450 $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<NO_CHECK_EOF
450 $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<NO_CHECK_EOF
451 > from __future__ import absolute_import
451 > from __future__ import absolute_import
452 > from extlibroot.recursedown.abs import detail as absdetail
452 > from extlibroot.recursedown.abs import detail as absdetail
453 > from .legacy import detail as legacydetail
453 > from .legacy import detail as legacydetail
454 > NO_CHECK_EOF
454 > NO_CHECK_EOF
455
455
456 Setup package that re-exports an attribute of its submodule as the same
456 Setup package that re-exports an attribute of its submodule as the same
457 name. This leaves 'shadowing.used' pointing to 'used.detail', but still
457 name. This leaves 'shadowing.used' pointing to 'used.detail', but still
458 the submodule 'used' should be somehow accessible. (issue5617)
458 the submodule 'used' should be somehow accessible. (issue5617)
459
459
460 $ mkdir -p $TESTTMP/extlibroot/shadowing
460 $ mkdir -p $TESTTMP/extlibroot/shadowing
461 $ cat > $TESTTMP/extlibroot/shadowing/used.py <<NO_CHECK_EOF
461 $ cat > $TESTTMP/extlibroot/shadowing/used.py <<NO_CHECK_EOF
462 > detail = b"this is extlibroot.shadowing.used"
462 > detail = b"this is extlibroot.shadowing.used"
463 > NO_CHECK_EOF
463 > NO_CHECK_EOF
464 $ cat > $TESTTMP/extlibroot/shadowing/proxied.py <<NO_CHECK_EOF
464 $ cat > $TESTTMP/extlibroot/shadowing/proxied.py <<NO_CHECK_EOF
465 > from __future__ import absolute_import
465 > from __future__ import absolute_import
466 > from extlibroot.shadowing.used import detail
466 > from extlibroot.shadowing.used import detail
467 > NO_CHECK_EOF
467 > NO_CHECK_EOF
468 $ cat > $TESTTMP/extlibroot/shadowing/__init__.py <<NO_CHECK_EOF
468 $ cat > $TESTTMP/extlibroot/shadowing/__init__.py <<NO_CHECK_EOF
469 > from __future__ import absolute_import
469 > from __future__ import absolute_import
470 > from .used import detail as used
470 > from .used import detail as used
471 > NO_CHECK_EOF
471 > NO_CHECK_EOF
472
472
473 Setup extension local modules to be imported with "absolute_import"
473 Setup extension local modules to be imported with "absolute_import"
474 feature.
474 feature.
475
475
476 $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2
476 $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2
477 $ touch $TESTTMP/absextroot/xsub1/__init__.py
477 $ touch $TESTTMP/absextroot/xsub1/__init__.py
478 $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py
478 $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py
479
479
480 $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<NO_CHECK_EOF
480 $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<NO_CHECK_EOF
481 > def func():
481 > def func():
482 > return b"this is absextroot.xsub1.xsub2.called.func()"
482 > return b"this is absextroot.xsub1.xsub2.called.func()"
483 > NO_CHECK_EOF
483 > NO_CHECK_EOF
484 $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<NO_CHECK_EOF
484 $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<NO_CHECK_EOF
485 > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally")
485 > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally")
486 > NO_CHECK_EOF
486 > NO_CHECK_EOF
487 $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<NO_CHECK_EOF
487 $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<NO_CHECK_EOF
488 > detail = b"this is absextroot.xsub1.xsub2.used"
488 > detail = b"this is absextroot.xsub1.xsub2.used"
489 > NO_CHECK_EOF
489 > NO_CHECK_EOF
490
490
491 Setup extension local modules to examine whether demand importing
491 Setup extension local modules to examine whether demand importing
492 works as expected in "level > 1" case.
492 works as expected in "level > 1" case.
493
493
494 $ cat > $TESTTMP/absextroot/relimportee.py <<NO_CHECK_EOF
494 $ cat > $TESTTMP/absextroot/relimportee.py <<NO_CHECK_EOF
495 > detail = b"this is absextroot.relimportee"
495 > detail = b"this is absextroot.relimportee"
496 > NO_CHECK_EOF
496 > NO_CHECK_EOF
497 $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<NO_CHECK_EOF
497 $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<NO_CHECK_EOF
498 > from __future__ import absolute_import
498 > from __future__ import absolute_import
499 > from mercurial import pycompat
499 > from mercurial import pycompat
500 > from ... import relimportee
500 > from ... import relimportee
501 > detail = b"this relimporter imports %r" % (
501 > detail = b"this relimporter imports %r" % (
502 > pycompat.bytestr(relimportee.detail))
502 > pycompat.bytestr(relimportee.detail))
503 > NO_CHECK_EOF
503 > NO_CHECK_EOF
504
504
505 Setup modules, which actually import extension local modules at
505 Setup modules, which actually import extension local modules at
506 runtime.
506 runtime.
507
507
508 $ cat > $TESTTMP/absextroot/absolute.py << NO_CHECK_EOF
508 $ cat > $TESTTMP/absextroot/absolute.py << NO_CHECK_EOF
509 > from __future__ import absolute_import
509 > from __future__ import absolute_import
510 >
510 >
511 > # import extension local modules absolutely (level = 0)
511 > # import extension local modules absolutely (level = 0)
512 > from absextroot.xsub1.xsub2 import used, unused
512 > from absextroot.xsub1.xsub2 import used, unused
513 > from absextroot.xsub1.xsub2.called import func
513 > from absextroot.xsub1.xsub2.called import func
514 >
514 >
515 > def getresult():
515 > def getresult():
516 > result = []
516 > result = []
517 > result.append(used.detail)
517 > result.append(used.detail)
518 > result.append(func())
518 > result.append(func())
519 > return result
519 > return result
520 > NO_CHECK_EOF
520 > NO_CHECK_EOF
521
521
522 $ cat > $TESTTMP/absextroot/relative.py << NO_CHECK_EOF
522 $ cat > $TESTTMP/absextroot/relative.py << NO_CHECK_EOF
523 > from __future__ import absolute_import
523 > from __future__ import absolute_import
524 >
524 >
525 > # import extension local modules relatively (level == 1)
525 > # import extension local modules relatively (level == 1)
526 > from .xsub1.xsub2 import used, unused
526 > from .xsub1.xsub2 import used, unused
527 > from .xsub1.xsub2.called import func
527 > from .xsub1.xsub2.called import func
528 >
528 >
529 > # import a module, which implies "importing with level > 1"
529 > # import a module, which implies "importing with level > 1"
530 > from .xsub1.xsub2 import relimporter
530 > from .xsub1.xsub2 import relimporter
531 >
531 >
532 > def getresult():
532 > def getresult():
533 > result = []
533 > result = []
534 > result.append(used.detail)
534 > result.append(used.detail)
535 > result.append(func())
535 > result.append(func())
536 > result.append(relimporter.detail)
536 > result.append(relimporter.detail)
537 > return result
537 > return result
538 > NO_CHECK_EOF
538 > NO_CHECK_EOF
539
539
540 Setup main procedure of extension.
540 Setup main procedure of extension.
541
541
542 $ cat > $TESTTMP/absextroot/__init__.py <<NO_CHECK_EOF
542 $ cat > $TESTTMP/absextroot/__init__.py <<NO_CHECK_EOF
543 > from __future__ import absolute_import
543 > from __future__ import absolute_import
544 > from mercurial import registrar
544 > from mercurial import registrar
545 > cmdtable = {}
545 > cmdtable = {}
546 > command = registrar.command(cmdtable)
546 > command = registrar.command(cmdtable)
547 >
547 >
548 > # "absolute" and "relative" shouldn't be imported before actual
548 > # "absolute" and "relative" shouldn't be imported before actual
549 > # command execution, because (1) they import same modules, and (2)
549 > # command execution, because (1) they import same modules, and (2)
550 > # preceding import (= instantiate "demandmod" object instead of
550 > # preceding import (= instantiate "demandmod" object instead of
551 > # real "module" object) might hide problem of succeeding import.
551 > # real "module" object) might hide problem of succeeding import.
552 >
552 >
553 > @command(b'showabsolute', [], norepo=True)
553 > @command(b'showabsolute', [], norepo=True)
554 > def showabsolute(ui, *args, **opts):
554 > def showabsolute(ui, *args, **opts):
555 > from absextroot import absolute
555 > from absextroot import absolute
556 > ui.write(b'ABS: %s\n' % b'\nABS: '.join(absolute.getresult()))
556 > ui.write(b'ABS: %s\n' % b'\nABS: '.join(absolute.getresult()))
557 >
557 >
558 > @command(b'showrelative', [], norepo=True)
558 > @command(b'showrelative', [], norepo=True)
559 > def showrelative(ui, *args, **opts):
559 > def showrelative(ui, *args, **opts):
560 > from . import relative
560 > from . import relative
561 > ui.write(b'REL: %s\n' % b'\nREL: '.join(relative.getresult()))
561 > ui.write(b'REL: %s\n' % b'\nREL: '.join(relative.getresult()))
562 >
562 >
563 > # import modules from external library
563 > # import modules from external library
564 > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused
564 > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused
565 > from extlibroot.lsub1.lsub2.called import func as lfunc
565 > from extlibroot.lsub1.lsub2.called import func as lfunc
566 > from extlibroot.recursedown import absdetail, legacydetail
566 > from extlibroot.recursedown import absdetail, legacydetail
567 > from extlibroot.shadowing import proxied
567 > from extlibroot.shadowing import proxied
568 >
568 >
569 > def uisetup(ui):
569 > def uisetup(ui):
570 > result = []
570 > result = []
571 > result.append(lused.detail)
571 > result.append(lused.detail)
572 > result.append(lfunc())
572 > result.append(lfunc())
573 > result.append(absdetail)
573 > result.append(absdetail)
574 > result.append(legacydetail)
574 > result.append(legacydetail)
575 > result.append(proxied.detail)
575 > result.append(proxied.detail)
576 > ui.write(b'LIB: %s\n' % b'\nLIB: '.join(result))
576 > ui.write(b'LIB: %s\n' % b'\nLIB: '.join(result))
577 > NO_CHECK_EOF
577 > NO_CHECK_EOF
578
578
579 Examine module importing.
579 Examine module importing.
580
580
581 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute)
581 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute)
582 LIB: this is extlibroot.lsub1.lsub2.used
582 LIB: this is extlibroot.lsub1.lsub2.used
583 LIB: this is extlibroot.lsub1.lsub2.called.func()
583 LIB: this is extlibroot.lsub1.lsub2.called.func()
584 LIB: this is extlibroot.recursedown.abs.used
584 LIB: this is extlibroot.recursedown.abs.used
585 LIB: this is extlibroot.recursedown.legacy.used
585 LIB: this is extlibroot.recursedown.legacy.used
586 LIB: this is extlibroot.shadowing.used
586 LIB: this is extlibroot.shadowing.used
587 ABS: this is absextroot.xsub1.xsub2.used
587 ABS: this is absextroot.xsub1.xsub2.used
588 ABS: this is absextroot.xsub1.xsub2.called.func()
588 ABS: this is absextroot.xsub1.xsub2.called.func()
589
589
590 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative)
590 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative)
591 LIB: this is extlibroot.lsub1.lsub2.used
591 LIB: this is extlibroot.lsub1.lsub2.used
592 LIB: this is extlibroot.lsub1.lsub2.called.func()
592 LIB: this is extlibroot.lsub1.lsub2.called.func()
593 LIB: this is extlibroot.recursedown.abs.used
593 LIB: this is extlibroot.recursedown.abs.used
594 LIB: this is extlibroot.recursedown.legacy.used
594 LIB: this is extlibroot.recursedown.legacy.used
595 LIB: this is extlibroot.shadowing.used
595 LIB: this is extlibroot.shadowing.used
596 REL: this is absextroot.xsub1.xsub2.used
596 REL: this is absextroot.xsub1.xsub2.used
597 REL: this is absextroot.xsub1.xsub2.called.func()
597 REL: this is absextroot.xsub1.xsub2.called.func()
598 REL: this relimporter imports 'this is absextroot.relimportee'
598 REL: this relimporter imports 'this is absextroot.relimportee'
599
599
600 Examine whether sub-module is imported relatively as expected.
600 Examine whether sub-module is imported relatively as expected.
601
601
602 See also issue5208 for detail about example case on Python 3.x.
602 See also issue5208 for detail about example case on Python 3.x.
603
603
604 $ f -q $TESTTMP/extlibroot/lsub1/lsub2/notexist.py
604 $ f -q $TESTTMP/extlibroot/lsub1/lsub2/notexist.py
605 $TESTTMP/extlibroot/lsub1/lsub2/notexist.py: file not found
605 $TESTTMP/extlibroot/lsub1/lsub2/notexist.py: file not found
606
606
607 $ cat > $TESTTMP/notexist.py <<NO_CHECK_EOF
607 $ cat > $TESTTMP/notexist.py <<NO_CHECK_EOF
608 > text = 'notexist.py at root is loaded unintentionally\n'
608 > text = 'notexist.py at root is loaded unintentionally\n'
609 > NO_CHECK_EOF
609 > NO_CHECK_EOF
610
610
611 $ cat > $TESTTMP/checkrelativity.py <<NO_CHECK_EOF
611 $ cat > $TESTTMP/checkrelativity.py <<NO_CHECK_EOF
612 > from mercurial import registrar
612 > from mercurial import registrar
613 > cmdtable = {}
613 > cmdtable = {}
614 > command = registrar.command(cmdtable)
614 > command = registrar.command(cmdtable)
615 >
615 >
616 > # demand import avoids failure of importing notexist here, but only on
616 > # demand import avoids failure of importing notexist here, but only on
617 > # Python 2.
617 > # Python 2.
618 > import extlibroot.lsub1.lsub2.notexist
618 > import extlibroot.lsub1.lsub2.notexist
619 >
619 >
620 > @command(b'checkrelativity', [], norepo=True)
620 > @command(b'checkrelativity', [], norepo=True)
621 > def checkrelativity(ui, *args, **opts):
621 > def checkrelativity(ui, *args, **opts):
622 > try:
622 > try:
623 > ui.write(extlibroot.lsub1.lsub2.notexist.text)
623 > ui.write(extlibroot.lsub1.lsub2.notexist.text)
624 > return 1 # unintentional success
624 > return 1 # unintentional success
625 > except ImportError:
625 > except ImportError:
626 > pass # intentional failure
626 > pass # intentional failure
627 > NO_CHECK_EOF
627 > NO_CHECK_EOF
628
628
629 Python 3's lazy importer verifies modules exist before returning the lazy
629 Python 3's lazy importer verifies modules exist before returning the lazy
630 module stub. Our custom lazy importer for Python 2 always returns a stub.
630 module stub. Our custom lazy importer for Python 2 always returns a stub.
631
631
632 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.checkrelativity=$TESTTMP/checkrelativity.py checkrelativity) || true
632 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.checkrelativity=$TESTTMP/checkrelativity.py checkrelativity) || true
633 *** failed to import extension checkrelativity from $TESTTMP/checkrelativity.py: No module named 'extlibroot.lsub1.lsub2.notexist' (py3 !)
633 *** failed to import extension checkrelativity from $TESTTMP/checkrelativity.py: No module named 'extlibroot.lsub1.lsub2.notexist' (py3 !)
634 hg: unknown command 'checkrelativity' (py3 !)
634 hg: unknown command 'checkrelativity' (py3 !)
635 (use 'hg help' for a list of commands) (py3 !)
635 (use 'hg help' for a list of commands) (py3 !)
636
636
637 #endif
637 #endif
638
638
639 (Here, module importing tests are finished. Therefore, use other than
639 (Here, module importing tests are finished. Therefore, use other than
640 NO_CHECK_* limit mark for heredoc python files, in order to apply
640 NO_CHECK_* limit mark for heredoc python files, in order to apply
641 import-checker.py or so on their contents)
641 import-checker.py or so on their contents)
642
642
643 Make sure a broken uisetup doesn't globally break hg:
643 Make sure a broken uisetup doesn't globally break hg:
644 $ cat > $TESTTMP/baduisetup.py <<EOF
644 $ cat > $TESTTMP/baduisetup.py <<EOF
645 > def uisetup(ui):
645 > def uisetup(ui):
646 > 1 / 0
646 > 1 / 0
647 > EOF
647 > EOF
648
648
649 Even though the extension fails during uisetup, hg is still basically usable:
649 Even though the extension fails during uisetup, hg is still basically usable:
650 $ hg --config extensions.baduisetup=$TESTTMP/baduisetup.py version
650 $ hg --config extensions.baduisetup=$TESTTMP/baduisetup.py version
651 Traceback (most recent call last):
651 Traceback (most recent call last):
652 File "*/mercurial/extensions.py", line *, in _runuisetup (glob)
652 File "*/mercurial/extensions.py", line *, in _runuisetup (glob)
653 uisetup(ui)
653 uisetup(ui)
654 File "$TESTTMP/baduisetup.py", line 2, in uisetup
654 File "$TESTTMP/baduisetup.py", line 2, in uisetup
655 1 / 0
655 1 / 0
656 ZeroDivisionError: * by zero (glob)
656 ZeroDivisionError: * by zero (glob)
657 *** failed to set up extension baduisetup: * by zero (glob)
657 *** failed to set up extension baduisetup: * by zero (glob)
658 Mercurial Distributed SCM (version *) (glob)
658 Mercurial Distributed SCM (version *) (glob)
659 (see https://mercurial-scm.org for more information)
659 (see https://mercurial-scm.org for more information)
660
660
661 Copyright (C) 2005-* Matt Mackall and others (glob)
661 Copyright (C) 2005-* Matt Mackall and others (glob)
662 This is free software; see the source for copying conditions. There is NO
662 This is free software; see the source for copying conditions. There is NO
663 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
663 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
664
664
665 $ cd ..
665 $ cd ..
666
666
667 hide outer repo
667 hide outer repo
668 $ hg init
668 $ hg init
669
669
670 $ cat > empty.py <<EOF
670 $ cat > empty.py <<EOF
671 > '''empty cmdtable
671 > '''empty cmdtable
672 > '''
672 > '''
673 > cmdtable = {}
673 > cmdtable = {}
674 > EOF
674 > EOF
675 $ emptypath=`pwd`/empty.py
675 $ emptypath=`pwd`/empty.py
676 $ echo "empty = $emptypath" >> $HGRCPATH
676 $ echo "empty = $emptypath" >> $HGRCPATH
677 $ hg help empty
677 $ hg help empty
678 empty extension - empty cmdtable
678 empty extension - empty cmdtable
679
679
680 no commands defined
680 no commands defined
681
681
682
682
683 $ echo 'empty = !' >> $HGRCPATH
683 $ echo 'empty = !' >> $HGRCPATH
684
684
685 $ cat > debugextension.py <<EOF
685 $ cat > debugextension.py <<EOF
686 > '''only debugcommands
686 > '''only debugcommands
687 > '''
687 > '''
688 > from mercurial import registrar
688 > from mercurial import registrar
689 > cmdtable = {}
689 > cmdtable = {}
690 > command = registrar.command(cmdtable)
690 > command = registrar.command(cmdtable)
691 > @command(b'debugfoobar', [], b'hg debugfoobar')
691 > @command(b'debugfoobar', [], b'hg debugfoobar')
692 > def debugfoobar(ui, repo, *args, **opts):
692 > def debugfoobar(ui, repo, *args, **opts):
693 > "yet another debug command"
693 > "yet another debug command"
694 > @command(b'foo', [], b'hg foo')
694 > @command(b'foo', [], b'hg foo')
695 > def foo(ui, repo, *args, **opts):
695 > def foo(ui, repo, *args, **opts):
696 > """yet another foo command
696 > """yet another foo command
697 > This command has been DEPRECATED since forever.
697 > This command has been DEPRECATED since forever.
698 > """
698 > """
699 > EOF
699 > EOF
700 $ debugpath=`pwd`/debugextension.py
700 $ debugpath=`pwd`/debugextension.py
701 $ echo "debugextension = $debugpath" >> $HGRCPATH
701 $ echo "debugextension = $debugpath" >> $HGRCPATH
702
702
703 $ hg help debugextension
703 $ hg help debugextension
704 hg debugextensions
704 hg debugextensions
705
705
706 show information about active extensions
706 show information about active extensions
707
707
708 options:
708 options:
709
709
710 -T --template TEMPLATE display with template
710 -T --template TEMPLATE display with template
711
711
712 (some details hidden, use --verbose to show complete help)
712 (some details hidden, use --verbose to show complete help)
713
713
714
714
715 $ hg --verbose help debugextension
715 $ hg --verbose help debugextension
716 hg debugextensions
716 hg debugextensions
717
717
718 show information about active extensions
718 show information about active extensions
719
719
720 options:
720 options:
721
721
722 -T --template TEMPLATE display with template
722 -T --template TEMPLATE display with template
723
723
724 global options ([+] can be repeated):
724 global options ([+] can be repeated):
725
725
726 -R --repository REPO repository root directory or name of overlay bundle
726 -R --repository REPO repository root directory or name of overlay bundle
727 file
727 file
728 --cwd DIR change working directory
728 --cwd DIR change working directory
729 -y --noninteractive do not prompt, automatically pick the first choice for
729 -y --noninteractive do not prompt, automatically pick the first choice for
730 all prompts
730 all prompts
731 -q --quiet suppress output
731 -q --quiet suppress output
732 -v --verbose enable additional output
732 -v --verbose enable additional output
733 --color TYPE when to colorize (boolean, always, auto, never, or
733 --color TYPE when to colorize (boolean, always, auto, never, or
734 debug)
734 debug)
735 --config CONFIG [+] set/override config option (use 'section.name=value')
735 --config CONFIG [+] set/override config option (use 'section.name=value')
736 --debug enable debugging output
736 --debug enable debugging output
737 --debugger start debugger
737 --debugger start debugger
738 --encoding ENCODE set the charset encoding (default: ascii)
738 --encoding ENCODE set the charset encoding (default: ascii)
739 --encodingmode MODE set the charset encoding mode (default: strict)
739 --encodingmode MODE set the charset encoding mode (default: strict)
740 --traceback always print a traceback on exception
740 --traceback always print a traceback on exception
741 --time time how long the command takes
741 --time time how long the command takes
742 --profile print command execution profile
742 --profile print command execution profile
743 --version output version information and exit
743 --version output version information and exit
744 -h --help display help and exit
744 -h --help display help and exit
745 --hidden consider hidden changesets
745 --hidden consider hidden changesets
746 --pager TYPE when to paginate (boolean, always, auto, or never)
746 --pager TYPE when to paginate (boolean, always, auto, or never)
747 (default: auto)
747 (default: auto)
748
748
749
749
750
750
751
751
752
752
753
753
754 $ hg --debug help debugextension
754 $ hg --debug help debugextension
755 hg debugextensions
755 hg debugextensions
756
756
757 show information about active extensions
757 show information about active extensions
758
758
759 options:
759 options:
760
760
761 -T --template TEMPLATE display with template
761 -T --template TEMPLATE display with template
762
762
763 global options ([+] can be repeated):
763 global options ([+] can be repeated):
764
764
765 -R --repository REPO repository root directory or name of overlay bundle
765 -R --repository REPO repository root directory or name of overlay bundle
766 file
766 file
767 --cwd DIR change working directory
767 --cwd DIR change working directory
768 -y --noninteractive do not prompt, automatically pick the first choice for
768 -y --noninteractive do not prompt, automatically pick the first choice for
769 all prompts
769 all prompts
770 -q --quiet suppress output
770 -q --quiet suppress output
771 -v --verbose enable additional output
771 -v --verbose enable additional output
772 --color TYPE when to colorize (boolean, always, auto, never, or
772 --color TYPE when to colorize (boolean, always, auto, never, or
773 debug)
773 debug)
774 --config CONFIG [+] set/override config option (use 'section.name=value')
774 --config CONFIG [+] set/override config option (use 'section.name=value')
775 --debug enable debugging output
775 --debug enable debugging output
776 --debugger start debugger
776 --debugger start debugger
777 --encoding ENCODE set the charset encoding (default: ascii)
777 --encoding ENCODE set the charset encoding (default: ascii)
778 --encodingmode MODE set the charset encoding mode (default: strict)
778 --encodingmode MODE set the charset encoding mode (default: strict)
779 --traceback always print a traceback on exception
779 --traceback always print a traceback on exception
780 --time time how long the command takes
780 --time time how long the command takes
781 --profile print command execution profile
781 --profile print command execution profile
782 --version output version information and exit
782 --version output version information and exit
783 -h --help display help and exit
783 -h --help display help and exit
784 --hidden consider hidden changesets
784 --hidden consider hidden changesets
785 --pager TYPE when to paginate (boolean, always, auto, or never)
785 --pager TYPE when to paginate (boolean, always, auto, or never)
786 (default: auto)
786 (default: auto)
787
787
788
788
789
789
790
790
791
791
792 $ echo 'debugextension = !' >> $HGRCPATH
792 $ echo 'debugextension = !' >> $HGRCPATH
793
793
794 Asking for help about a deprecated extension should do something useful:
794 Asking for help about a deprecated extension should do something useful:
795
795
796 $ hg help glog
796 $ hg help glog
797 'glog' is provided by the following extension:
797 'glog' is provided by the following extension:
798
798
799 graphlog command to view revision graphs from a shell (DEPRECATED)
799 graphlog command to view revision graphs from a shell (DEPRECATED)
800
800
801 (use 'hg help extensions' for information on enabling extensions)
801 (use 'hg help extensions' for information on enabling extensions)
802
802
803 Extension module help vs command help:
803 Extension module help vs command help:
804
804
805 $ echo 'extdiff =' >> $HGRCPATH
805 $ echo 'extdiff =' >> $HGRCPATH
806 $ hg help extdiff
806 $ hg help extdiff
807 hg extdiff [OPT]... [FILE]...
807 hg extdiff [OPT]... [FILE]...
808
808
809 use external program to diff repository (or selected files)
809 use external program to diff repository (or selected files)
810
810
811 Show differences between revisions for the specified files, using an
811 Show differences between revisions for the specified files, using an
812 external program. The default program used is diff, with default options
812 external program. The default program used is diff, with default options
813 "-Npru".
813 "-Npru".
814
814
815 To select a different program, use the -p/--program option. The program
815 To select a different program, use the -p/--program option. The program
816 will be passed the names of two directories to compare, unless the --per-
816 will be passed the names of two directories to compare, unless the --per-
817 file option is specified (see below). To pass additional options to the
817 file option is specified (see below). To pass additional options to the
818 program, use -o/--option. These will be passed before the names of the
818 program, use -o/--option. These will be passed before the names of the
819 directories or files to compare.
819 directories or files to compare.
820
820
821 When two revision arguments are given, then changes are shown between
821 When two revision arguments are given, then changes are shown between
822 those revisions. If only one revision is specified then that revision is
822 those revisions. If only one revision is specified then that revision is
823 compared to the working directory, and, when no revisions are specified,
823 compared to the working directory, and, when no revisions are specified,
824 the working directory files are compared to its parent.
824 the working directory files are compared to its parent.
825
825
826 The --per-file option runs the external program repeatedly on each file to
826 The --per-file option runs the external program repeatedly on each file to
827 diff, instead of once on two directories. By default, this happens one by
827 diff, instead of once on two directories. By default, this happens one by
828 one, where the next file diff is open in the external program only once
828 one, where the next file diff is open in the external program only once
829 the previous external program (for the previous file diff) has exited. If
829 the previous external program (for the previous file diff) has exited. If
830 the external program has a graphical interface, it can open all the file
830 the external program has a graphical interface, it can open all the file
831 diffs at once instead of one by one. See 'hg help -e extdiff' for
831 diffs at once instead of one by one. See 'hg help -e extdiff' for
832 information about how to tell Mercurial that a given program has a
832 information about how to tell Mercurial that a given program has a
833 graphical interface.
833 graphical interface.
834
834
835 The --confirm option will prompt the user before each invocation of the
835 The --confirm option will prompt the user before each invocation of the
836 external program. It is ignored if --per-file isn't specified.
836 external program. It is ignored if --per-file isn't specified.
837
837
838 (use 'hg help -e extdiff' to show help for the extdiff extension)
838 (use 'hg help -e extdiff' to show help for the extdiff extension)
839
839
840 options ([+] can be repeated):
840 options ([+] can be repeated):
841
841
842 -p --program CMD comparison program to run
842 -p --program CMD comparison program to run
843 -o --option OPT [+] pass option to comparison program
843 -o --option OPT [+] pass option to comparison program
844 -r --rev REV [+] revision
844 -r --rev REV [+] revision
845 -c --change REV change made by revision
845 -c --change REV change made by revision
846 --per-file compare each file instead of revision snapshots
846 --per-file compare each file instead of revision snapshots
847 --confirm prompt user before each external program invocation
847 --confirm prompt user before each external program invocation
848 --patch compare patches for two revisions
848 --patch compare patches for two revisions
849 -I --include PATTERN [+] include names matching the given patterns
849 -I --include PATTERN [+] include names matching the given patterns
850 -X --exclude PATTERN [+] exclude names matching the given patterns
850 -X --exclude PATTERN [+] exclude names matching the given patterns
851 -S --subrepos recurse into subrepositories
851 -S --subrepos recurse into subrepositories
852
852
853 (some details hidden, use --verbose to show complete help)
853 (some details hidden, use --verbose to show complete help)
854
854
855
855
856
856
857
857
858
858
859
859
860
860
861
861
862
862
863
863
864 $ hg help --extension extdiff
864 $ hg help --extension extdiff
865 extdiff extension - command to allow external programs to compare revisions
865 extdiff extension - command to allow external programs to compare revisions
866
866
867 The extdiff Mercurial extension allows you to use external programs to compare
867 The extdiff Mercurial extension allows you to use external programs to compare
868 revisions, or revision with working directory. The external diff programs are
868 revisions, or revision with working directory. The external diff programs are
869 called with a configurable set of options and two non-option arguments: paths
869 called with a configurable set of options and two non-option arguments: paths
870 to directories containing snapshots of files to compare.
870 to directories containing snapshots of files to compare.
871
871
872 If there is more than one file being compared and the "child" revision is the
872 If there is more than one file being compared and the "child" revision is the
873 working directory, any modifications made in the external diff program will be
873 working directory, any modifications made in the external diff program will be
874 copied back to the working directory from the temporary directory.
874 copied back to the working directory from the temporary directory.
875
875
876 The extdiff extension also allows you to configure new diff commands, so you
876 The extdiff extension also allows you to configure new diff commands, so you
877 do not need to type 'hg extdiff -p kdiff3' always.
877 do not need to type 'hg extdiff -p kdiff3' always.
878
878
879 [extdiff]
879 [extdiff]
880 # add new command that runs GNU diff(1) in 'context diff' mode
880 # add new command that runs GNU diff(1) in 'context diff' mode
881 cdiff = gdiff -Nprc5
881 cdiff = gdiff -Nprc5
882 ## or the old way:
882 ## or the old way:
883 #cmd.cdiff = gdiff
883 #cmd.cdiff = gdiff
884 #opts.cdiff = -Nprc5
884 #opts.cdiff = -Nprc5
885
885
886 # add new command called meld, runs meld (no need to name twice). If
886 # add new command called meld, runs meld (no need to name twice). If
887 # the meld executable is not available, the meld tool in [merge-tools]
887 # the meld executable is not available, the meld tool in [merge-tools]
888 # will be used, if available
888 # will be used, if available
889 meld =
889 meld =
890
890
891 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
891 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
892 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
892 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
893 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
893 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
894 # your .vimrc
894 # your .vimrc
895 vimdiff = gvim -f "+next" \
895 vimdiff = gvim -f "+next" \
896 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
896 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
897
897
898 Tool arguments can include variables that are expanded at runtime:
898 Tool arguments can include variables that are expanded at runtime:
899
899
900 $parent1, $plabel1 - filename, descriptive label of first parent
900 $parent1, $plabel1 - filename, descriptive label of first parent
901 $child, $clabel - filename, descriptive label of child revision
901 $child, $clabel - filename, descriptive label of child revision
902 $parent2, $plabel2 - filename, descriptive label of second parent
902 $parent2, $plabel2 - filename, descriptive label of second parent
903 $root - repository root
903 $root - repository root
904 $parent is an alias for $parent1.
904 $parent is an alias for $parent1.
905
905
906 The extdiff extension will look in your [diff-tools] and [merge-tools]
906 The extdiff extension will look in your [diff-tools] and [merge-tools]
907 sections for diff tool arguments, when none are specified in [extdiff].
907 sections for diff tool arguments, when none are specified in [extdiff].
908
908
909 [extdiff]
909 [extdiff]
910 kdiff3 =
910 kdiff3 =
911
911
912 [diff-tools]
912 [diff-tools]
913 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
913 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
914
914
915 If a program has a graphical interface, it might be interesting to tell
915 If a program has a graphical interface, it might be interesting to tell
916 Mercurial about it. It will prevent the program from being mistakenly used in
916 Mercurial about it. It will prevent the program from being mistakenly used in
917 a terminal-only environment (such as an SSH terminal session), and will make
917 a terminal-only environment (such as an SSH terminal session), and will make
918 'hg extdiff --per-file' open multiple file diffs at once instead of one by one
918 'hg extdiff --per-file' open multiple file diffs at once instead of one by one
919 (if you still want to open file diffs one by one, you can use the --confirm
919 (if you still want to open file diffs one by one, you can use the --confirm
920 option).
920 option).
921
921
922 Declaring that a tool has a graphical interface can be done with the "gui"
922 Declaring that a tool has a graphical interface can be done with the "gui"
923 flag next to where "diffargs" are specified:
923 flag next to where "diffargs" are specified:
924
924
925 [diff-tools]
925 [diff-tools]
926 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
926 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
927 kdiff3.gui = true
927 kdiff3.gui = true
928
928
929 You can use -I/-X and list of file or directory names like normal 'hg diff'
929 You can use -I/-X and list of file or directory names like normal 'hg diff'
930 command. The extdiff extension makes snapshots of only needed files, so
930 command. The extdiff extension makes snapshots of only needed files, so
931 running the external diff program will actually be pretty fast (at least
931 running the external diff program will actually be pretty fast (at least
932 faster than having to compare the entire tree).
932 faster than having to compare the entire tree).
933
933
934 list of commands:
934 list of commands:
935
935
936 extdiff use external program to diff repository (or selected files)
936 extdiff use external program to diff repository (or selected files)
937
937
938 (use 'hg help -v -e extdiff' to show built-in aliases and global options)
938 (use 'hg help -v -e extdiff' to show built-in aliases and global options)
939
939
940
940
941
941
942
942
943
943
944
944
945
945
946
946
947
947
948
948
949
949
950
950
951
951
952
952
953
953
954
954
955 $ echo 'extdiff = !' >> $HGRCPATH
955 $ echo 'extdiff = !' >> $HGRCPATH
956
956
957 Test help topic with same name as extension
957 Test help topic with same name as extension
958
958
959 $ cat > multirevs.py <<EOF
959 $ cat > multirevs.py <<EOF
960 > from mercurial import commands, registrar
960 > from mercurial import commands, registrar
961 > cmdtable = {}
961 > cmdtable = {}
962 > command = registrar.command(cmdtable)
962 > command = registrar.command(cmdtable)
963 > """multirevs extension
963 > """multirevs extension
964 > Big multi-line module docstring."""
964 > Big multi-line module docstring."""
965 > @command(b'multirevs', [], b'ARG', norepo=True)
965 > @command(b'multirevs', [], b'ARG', norepo=True)
966 > def multirevs(ui, repo, arg, *args, **opts):
966 > def multirevs(ui, repo, arg, *args, **opts):
967 > """multirevs command"""
967 > """multirevs command"""
968 > EOF
968 > EOF
969 $ echo "multirevs = multirevs.py" >> $HGRCPATH
969 $ echo "multirevs = multirevs.py" >> $HGRCPATH
970
970
971 $ hg help multirevs | tail
971 $ hg help multirevs | tail
972 used):
972 used):
973
973
974 hg update :@
974 hg update :@
975
975
976 - Show diff between tags 1.3 and 1.5 (this works because the first and the
976 - Show diff between tags 1.3 and 1.5 (this works because the first and the
977 last revisions of the revset are used):
977 last revisions of the revset are used):
978
978
979 hg diff -r 1.3::1.5
979 hg diff -r 1.3::1.5
980
980
981 use 'hg help -c multirevs' to see help for the multirevs command
981 use 'hg help -c multirevs' to see help for the multirevs command
982
982
983
983
984
984
985
985
986
986
987
987
988 $ hg help -c multirevs
988 $ hg help -c multirevs
989 hg multirevs ARG
989 hg multirevs ARG
990
990
991 multirevs command
991 multirevs command
992
992
993 (some details hidden, use --verbose to show complete help)
993 (some details hidden, use --verbose to show complete help)
994
994
995
995
996
996
997 $ hg multirevs
997 $ hg multirevs
998 hg multirevs: invalid arguments
998 hg multirevs: invalid arguments
999 hg multirevs ARG
999 hg multirevs ARG
1000
1000
1001 multirevs command
1001 multirevs command
1002
1002
1003 (use 'hg multirevs -h' to show more help)
1003 (use 'hg multirevs -h' to show more help)
1004 [255]
1004 [255]
1005
1005
1006
1006
1007
1007
1008 $ echo "multirevs = !" >> $HGRCPATH
1008 $ echo "multirevs = !" >> $HGRCPATH
1009
1009
1010 Issue811: Problem loading extensions twice (by site and by user)
1010 Issue811: Problem loading extensions twice (by site and by user)
1011
1011
1012 $ cat <<EOF >> $HGRCPATH
1012 $ cat <<EOF >> $HGRCPATH
1013 > mq =
1013 > mq =
1014 > strip =
1014 > strip =
1015 > hgext.mq =
1015 > hgext.mq =
1016 > hgext/mq =
1016 > hgext/mq =
1017 > EOF
1017 > EOF
1018
1018
1019 Show extensions:
1019 Show extensions:
1020 (note that mq force load strip, also checking it's not loaded twice)
1020 (note that mq force load strip, also checking it's not loaded twice)
1021
1021
1022 #if no-extraextensions
1022 #if no-extraextensions
1023 $ hg debugextensions
1023 $ hg debugextensions
1024 mq
1024 mq
1025 strip
1025 strip
1026 #endif
1026 #endif
1027
1027
1028 For extensions, which name matches one of its commands, help
1028 For extensions, which name matches one of its commands, help
1029 message should ask '-v -e' to get list of built-in aliases
1029 message should ask '-v -e' to get list of built-in aliases
1030 along with extension help itself
1030 along with extension help itself
1031
1031
1032 $ mkdir $TESTTMP/d
1032 $ mkdir $TESTTMP/d
1033 $ cat > $TESTTMP/d/dodo.py <<EOF
1033 $ cat > $TESTTMP/d/dodo.py <<EOF
1034 > """
1034 > """
1035 > This is an awesome 'dodo' extension. It does nothing and
1035 > This is an awesome 'dodo' extension. It does nothing and
1036 > writes 'Foo foo'
1036 > writes 'Foo foo'
1037 > """
1037 > """
1038 > from mercurial import commands, registrar
1038 > from mercurial import commands, registrar
1039 > cmdtable = {}
1039 > cmdtable = {}
1040 > command = registrar.command(cmdtable)
1040 > command = registrar.command(cmdtable)
1041 > @command(b'dodo', [], b'hg dodo')
1041 > @command(b'dodo', [], b'hg dodo')
1042 > def dodo(ui, *args, **kwargs):
1042 > def dodo(ui, *args, **kwargs):
1043 > """Does nothing"""
1043 > """Does nothing"""
1044 > ui.write(b"I do nothing. Yay\\n")
1044 > ui.write(b"I do nothing. Yay\\n")
1045 > @command(b'foofoo', [], b'hg foofoo')
1045 > @command(b'foofoo', [], b'hg foofoo')
1046 > def foofoo(ui, *args, **kwargs):
1046 > def foofoo(ui, *args, **kwargs):
1047 > """Writes 'Foo foo'"""
1047 > """Writes 'Foo foo'"""
1048 > ui.write(b"Foo foo\\n")
1048 > ui.write(b"Foo foo\\n")
1049 > EOF
1049 > EOF
1050 $ dodopath=$TESTTMP/d/dodo.py
1050 $ dodopath=$TESTTMP/d/dodo.py
1051
1051
1052 $ echo "dodo = $dodopath" >> $HGRCPATH
1052 $ echo "dodo = $dodopath" >> $HGRCPATH
1053
1053
1054 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
1054 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
1055 $ hg help -e dodo
1055 $ hg help -e dodo
1056 dodo extension -
1056 dodo extension -
1057
1057
1058 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
1058 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
1059
1059
1060 list of commands:
1060 list of commands:
1061
1061
1062 dodo Does nothing
1062 dodo Does nothing
1063 foofoo Writes 'Foo foo'
1063 foofoo Writes 'Foo foo'
1064
1064
1065 (use 'hg help -v -e dodo' to show built-in aliases and global options)
1065 (use 'hg help -v -e dodo' to show built-in aliases and global options)
1066
1066
1067 Make sure that '-v -e' prints list of built-in aliases along with
1067 Make sure that '-v -e' prints list of built-in aliases along with
1068 extension help itself
1068 extension help itself
1069 $ hg help -v -e dodo
1069 $ hg help -v -e dodo
1070 dodo extension -
1070 dodo extension -
1071
1071
1072 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
1072 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
1073
1073
1074 list of commands:
1074 list of commands:
1075
1075
1076 dodo Does nothing
1076 dodo Does nothing
1077 foofoo Writes 'Foo foo'
1077 foofoo Writes 'Foo foo'
1078
1078
1079 global options ([+] can be repeated):
1079 global options ([+] can be repeated):
1080
1080
1081 -R --repository REPO repository root directory or name of overlay bundle
1081 -R --repository REPO repository root directory or name of overlay bundle
1082 file
1082 file
1083 --cwd DIR change working directory
1083 --cwd DIR change working directory
1084 -y --noninteractive do not prompt, automatically pick the first choice for
1084 -y --noninteractive do not prompt, automatically pick the first choice for
1085 all prompts
1085 all prompts
1086 -q --quiet suppress output
1086 -q --quiet suppress output
1087 -v --verbose enable additional output
1087 -v --verbose enable additional output
1088 --color TYPE when to colorize (boolean, always, auto, never, or
1088 --color TYPE when to colorize (boolean, always, auto, never, or
1089 debug)
1089 debug)
1090 --config CONFIG [+] set/override config option (use 'section.name=value')
1090 --config CONFIG [+] set/override config option (use 'section.name=value')
1091 --debug enable debugging output
1091 --debug enable debugging output
1092 --debugger start debugger
1092 --debugger start debugger
1093 --encoding ENCODE set the charset encoding (default: ascii)
1093 --encoding ENCODE set the charset encoding (default: ascii)
1094 --encodingmode MODE set the charset encoding mode (default: strict)
1094 --encodingmode MODE set the charset encoding mode (default: strict)
1095 --traceback always print a traceback on exception
1095 --traceback always print a traceback on exception
1096 --time time how long the command takes
1096 --time time how long the command takes
1097 --profile print command execution profile
1097 --profile print command execution profile
1098 --version output version information and exit
1098 --version output version information and exit
1099 -h --help display help and exit
1099 -h --help display help and exit
1100 --hidden consider hidden changesets
1100 --hidden consider hidden changesets
1101 --pager TYPE when to paginate (boolean, always, auto, or never)
1101 --pager TYPE when to paginate (boolean, always, auto, or never)
1102 (default: auto)
1102 (default: auto)
1103
1103
1104 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
1104 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
1105 $ hg help -v dodo
1105 $ hg help -v dodo
1106 hg dodo
1106 hg dodo
1107
1107
1108 Does nothing
1108 Does nothing
1109
1109
1110 (use 'hg help -e dodo' to show help for the dodo extension)
1110 (use 'hg help -e dodo' to show help for the dodo extension)
1111
1111
1112 options:
1112 options:
1113
1113
1114 --mq operate on patch repository
1114 --mq operate on patch repository
1115
1115
1116 global options ([+] can be repeated):
1116 global options ([+] can be repeated):
1117
1117
1118 -R --repository REPO repository root directory or name of overlay bundle
1118 -R --repository REPO repository root directory or name of overlay bundle
1119 file
1119 file
1120 --cwd DIR change working directory
1120 --cwd DIR change working directory
1121 -y --noninteractive do not prompt, automatically pick the first choice for
1121 -y --noninteractive do not prompt, automatically pick the first choice for
1122 all prompts
1122 all prompts
1123 -q --quiet suppress output
1123 -q --quiet suppress output
1124 -v --verbose enable additional output
1124 -v --verbose enable additional output
1125 --color TYPE when to colorize (boolean, always, auto, never, or
1125 --color TYPE when to colorize (boolean, always, auto, never, or
1126 debug)
1126 debug)
1127 --config CONFIG [+] set/override config option (use 'section.name=value')
1127 --config CONFIG [+] set/override config option (use 'section.name=value')
1128 --debug enable debugging output
1128 --debug enable debugging output
1129 --debugger start debugger
1129 --debugger start debugger
1130 --encoding ENCODE set the charset encoding (default: ascii)
1130 --encoding ENCODE set the charset encoding (default: ascii)
1131 --encodingmode MODE set the charset encoding mode (default: strict)
1131 --encodingmode MODE set the charset encoding mode (default: strict)
1132 --traceback always print a traceback on exception
1132 --traceback always print a traceback on exception
1133 --time time how long the command takes
1133 --time time how long the command takes
1134 --profile print command execution profile
1134 --profile print command execution profile
1135 --version output version information and exit
1135 --version output version information and exit
1136 -h --help display help and exit
1136 -h --help display help and exit
1137 --hidden consider hidden changesets
1137 --hidden consider hidden changesets
1138 --pager TYPE when to paginate (boolean, always, auto, or never)
1138 --pager TYPE when to paginate (boolean, always, auto, or never)
1139 (default: auto)
1139 (default: auto)
1140
1140
1141 In case when extension name doesn't match any of its commands,
1141 In case when extension name doesn't match any of its commands,
1142 help message should ask for '-v' to get list of built-in aliases
1142 help message should ask for '-v' to get list of built-in aliases
1143 along with extension help
1143 along with extension help
1144 $ cat > $TESTTMP/d/dudu.py <<EOF
1144 $ cat > $TESTTMP/d/dudu.py <<EOF
1145 > """
1145 > """
1146 > This is an awesome 'dudu' extension. It does something and
1146 > This is an awesome 'dudu' extension. It does something and
1147 > also writes 'Beep beep'
1147 > also writes 'Beep beep'
1148 > """
1148 > """
1149 > from mercurial import commands, registrar
1149 > from mercurial import commands, registrar
1150 > cmdtable = {}
1150 > cmdtable = {}
1151 > command = registrar.command(cmdtable)
1151 > command = registrar.command(cmdtable)
1152 > @command(b'something', [], b'hg something')
1152 > @command(b'something', [], b'hg something')
1153 > def something(ui, *args, **kwargs):
1153 > def something(ui, *args, **kwargs):
1154 > """Does something"""
1154 > """Does something"""
1155 > ui.write(b"I do something. Yaaay\\n")
1155 > ui.write(b"I do something. Yaaay\\n")
1156 > @command(b'beep', [], b'hg beep')
1156 > @command(b'beep', [], b'hg beep')
1157 > def beep(ui, *args, **kwargs):
1157 > def beep(ui, *args, **kwargs):
1158 > """Writes 'Beep beep'"""
1158 > """Writes 'Beep beep'"""
1159 > ui.write(b"Beep beep\\n")
1159 > ui.write(b"Beep beep\\n")
1160 > EOF
1160 > EOF
1161 $ dudupath=$TESTTMP/d/dudu.py
1161 $ dudupath=$TESTTMP/d/dudu.py
1162
1162
1163 $ echo "dudu = $dudupath" >> $HGRCPATH
1163 $ echo "dudu = $dudupath" >> $HGRCPATH
1164
1164
1165 $ hg help -e dudu
1165 $ hg help -e dudu
1166 dudu extension -
1166 dudu extension -
1167
1167
1168 This is an awesome 'dudu' extension. It does something and also writes 'Beep
1168 This is an awesome 'dudu' extension. It does something and also writes 'Beep
1169 beep'
1169 beep'
1170
1170
1171 list of commands:
1171 list of commands:
1172
1172
1173 beep Writes 'Beep beep'
1173 beep Writes 'Beep beep'
1174 something Does something
1174 something Does something
1175
1175
1176 (use 'hg help -v dudu' to show built-in aliases and global options)
1176 (use 'hg help -v dudu' to show built-in aliases and global options)
1177
1177
1178 In case when extension name doesn't match any of its commands,
1178 In case when extension name doesn't match any of its commands,
1179 help options '-v' and '-v -e' should be equivalent
1179 help options '-v' and '-v -e' should be equivalent
1180 $ hg help -v dudu
1180 $ hg help -v dudu
1181 dudu extension -
1181 dudu extension -
1182
1182
1183 This is an awesome 'dudu' extension. It does something and also writes 'Beep
1183 This is an awesome 'dudu' extension. It does something and also writes 'Beep
1184 beep'
1184 beep'
1185
1185
1186 list of commands:
1186 list of commands:
1187
1187
1188 beep Writes 'Beep beep'
1188 beep Writes 'Beep beep'
1189 something Does something
1189 something Does something
1190
1190
1191 global options ([+] can be repeated):
1191 global options ([+] can be repeated):
1192
1192
1193 -R --repository REPO repository root directory or name of overlay bundle
1193 -R --repository REPO repository root directory or name of overlay bundle
1194 file
1194 file
1195 --cwd DIR change working directory
1195 --cwd DIR change working directory
1196 -y --noninteractive do not prompt, automatically pick the first choice for
1196 -y --noninteractive do not prompt, automatically pick the first choice for
1197 all prompts
1197 all prompts
1198 -q --quiet suppress output
1198 -q --quiet suppress output
1199 -v --verbose enable additional output
1199 -v --verbose enable additional output
1200 --color TYPE when to colorize (boolean, always, auto, never, or
1200 --color TYPE when to colorize (boolean, always, auto, never, or
1201 debug)
1201 debug)
1202 --config CONFIG [+] set/override config option (use 'section.name=value')
1202 --config CONFIG [+] set/override config option (use 'section.name=value')
1203 --debug enable debugging output
1203 --debug enable debugging output
1204 --debugger start debugger
1204 --debugger start debugger
1205 --encoding ENCODE set the charset encoding (default: ascii)
1205 --encoding ENCODE set the charset encoding (default: ascii)
1206 --encodingmode MODE set the charset encoding mode (default: strict)
1206 --encodingmode MODE set the charset encoding mode (default: strict)
1207 --traceback always print a traceback on exception
1207 --traceback always print a traceback on exception
1208 --time time how long the command takes
1208 --time time how long the command takes
1209 --profile print command execution profile
1209 --profile print command execution profile
1210 --version output version information and exit
1210 --version output version information and exit
1211 -h --help display help and exit
1211 -h --help display help and exit
1212 --hidden consider hidden changesets
1212 --hidden consider hidden changesets
1213 --pager TYPE when to paginate (boolean, always, auto, or never)
1213 --pager TYPE when to paginate (boolean, always, auto, or never)
1214 (default: auto)
1214 (default: auto)
1215
1215
1216 $ hg help -v -e dudu
1216 $ hg help -v -e dudu
1217 dudu extension -
1217 dudu extension -
1218
1218
1219 This is an awesome 'dudu' extension. It does something and also writes 'Beep
1219 This is an awesome 'dudu' extension. It does something and also writes 'Beep
1220 beep'
1220 beep'
1221
1221
1222 list of commands:
1222 list of commands:
1223
1223
1224 beep Writes 'Beep beep'
1224 beep Writes 'Beep beep'
1225 something Does something
1225 something Does something
1226
1226
1227 global options ([+] can be repeated):
1227 global options ([+] can be repeated):
1228
1228
1229 -R --repository REPO repository root directory or name of overlay bundle
1229 -R --repository REPO repository root directory or name of overlay bundle
1230 file
1230 file
1231 --cwd DIR change working directory
1231 --cwd DIR change working directory
1232 -y --noninteractive do not prompt, automatically pick the first choice for
1232 -y --noninteractive do not prompt, automatically pick the first choice for
1233 all prompts
1233 all prompts
1234 -q --quiet suppress output
1234 -q --quiet suppress output
1235 -v --verbose enable additional output
1235 -v --verbose enable additional output
1236 --color TYPE when to colorize (boolean, always, auto, never, or
1236 --color TYPE when to colorize (boolean, always, auto, never, or
1237 debug)
1237 debug)
1238 --config CONFIG [+] set/override config option (use 'section.name=value')
1238 --config CONFIG [+] set/override config option (use 'section.name=value')
1239 --debug enable debugging output
1239 --debug enable debugging output
1240 --debugger start debugger
1240 --debugger start debugger
1241 --encoding ENCODE set the charset encoding (default: ascii)
1241 --encoding ENCODE set the charset encoding (default: ascii)
1242 --encodingmode MODE set the charset encoding mode (default: strict)
1242 --encodingmode MODE set the charset encoding mode (default: strict)
1243 --traceback always print a traceback on exception
1243 --traceback always print a traceback on exception
1244 --time time how long the command takes
1244 --time time how long the command takes
1245 --profile print command execution profile
1245 --profile print command execution profile
1246 --version output version information and exit
1246 --version output version information and exit
1247 -h --help display help and exit
1247 -h --help display help and exit
1248 --hidden consider hidden changesets
1248 --hidden consider hidden changesets
1249 --pager TYPE when to paginate (boolean, always, auto, or never)
1249 --pager TYPE when to paginate (boolean, always, auto, or never)
1250 (default: auto)
1250 (default: auto)
1251
1251
1252 Disabled extension commands:
1252 Disabled extension commands:
1253
1253
1254 $ ORGHGRCPATH=$HGRCPATH
1254 $ ORGHGRCPATH=$HGRCPATH
1255 $ HGRCPATH=
1255 $ HGRCPATH=
1256 $ export HGRCPATH
1256 $ export HGRCPATH
1257 $ hg help email
1257 $ hg help email
1258 'email' is provided by the following extension:
1258 'email' is provided by the following extension:
1259
1259
1260 patchbomb command to send changesets as (a series of) patch emails
1260 patchbomb command to send changesets as (a series of) patch emails
1261
1261
1262 (use 'hg help extensions' for information on enabling extensions)
1262 (use 'hg help extensions' for information on enabling extensions)
1263
1263
1264
1264
1265 $ hg qdel
1265 $ hg qdel
1266 hg: unknown command 'qdel'
1266 hg: unknown command 'qdel'
1267 'qdelete' is provided by the following extension:
1267 'qdelete' is provided by the following extension:
1268
1268
1269 mq manage a stack of patches
1269 mq manage a stack of patches
1270
1270
1271 (use 'hg help extensions' for information on enabling extensions)
1271 (use 'hg help extensions' for information on enabling extensions)
1272 [255]
1272 [255]
1273
1273
1274
1274
1275 $ hg churn
1275 $ hg churn
1276 hg: unknown command 'churn'
1276 hg: unknown command 'churn'
1277 'churn' is provided by the following extension:
1277 'churn' is provided by the following extension:
1278
1278
1279 churn command to display statistics about repository history
1279 churn command to display statistics about repository history
1280
1280
1281 (use 'hg help extensions' for information on enabling extensions)
1281 (use 'hg help extensions' for information on enabling extensions)
1282 [255]
1282 [255]
1283
1283
1284
1284
1285
1285
1286 Disabled extensions:
1286 Disabled extensions:
1287
1287
1288 $ hg help churn
1288 $ hg help churn
1289 churn extension - command to display statistics about repository history
1289 churn extension - command to display statistics about repository history
1290
1290
1291 (use 'hg help extensions' for information on enabling extensions)
1291 (use 'hg help extensions' for information on enabling extensions)
1292
1292
1293 $ hg help patchbomb
1293 $ hg help patchbomb
1294 patchbomb extension - command to send changesets as (a series of) patch emails
1294 patchbomb extension - command to send changesets as (a series of) patch emails
1295
1295
1296 The series is started off with a "[PATCH 0 of N]" introduction, which
1296 The series is started off with a "[PATCH 0 of N]" introduction, which
1297 describes the series as a whole.
1297 describes the series as a whole.
1298
1298
1299 Each patch email has a Subject line of "[PATCH M of N] ...", using the first
1299 Each patch email has a Subject line of "[PATCH M of N] ...", using the first
1300 line of the changeset description as the subject text. The message contains
1300 line of the changeset description as the subject text. The message contains
1301 two or three body parts:
1301 two or three body parts:
1302
1302
1303 - The changeset description.
1303 - The changeset description.
1304 - [Optional] The result of running diffstat on the patch.
1304 - [Optional] The result of running diffstat on the patch.
1305 - The patch itself, as generated by 'hg export'.
1305 - The patch itself, as generated by 'hg export'.
1306
1306
1307 Each message refers to the first in the series using the In-Reply-To and
1307 Each message refers to the first in the series using the In-Reply-To and
1308 References headers, so they will show up as a sequence in threaded mail and
1308 References headers, so they will show up as a sequence in threaded mail and
1309 news readers, and in mail archives.
1309 news readers, and in mail archives.
1310
1310
1311 To configure other defaults, add a section like this to your configuration
1311 To configure other defaults, add a section like this to your configuration
1312 file:
1312 file:
1313
1313
1314 [email]
1314 [email]
1315 from = My Name <my@email>
1315 from = My Name <my@email>
1316 to = recipient1, recipient2, ...
1316 to = recipient1, recipient2, ...
1317 cc = cc1, cc2, ...
1317 cc = cc1, cc2, ...
1318 bcc = bcc1, bcc2, ...
1318 bcc = bcc1, bcc2, ...
1319 reply-to = address1, address2, ...
1319 reply-to = address1, address2, ...
1320
1320
1321 Use "[patchbomb]" as configuration section name if you need to override global
1321 Use "[patchbomb]" as configuration section name if you need to override global
1322 "[email]" address settings.
1322 "[email]" address settings.
1323
1323
1324 Then you can use the 'hg email' command to mail a series of changesets as a
1324 Then you can use the 'hg email' command to mail a series of changesets as a
1325 patchbomb.
1325 patchbomb.
1326
1326
1327 You can also either configure the method option in the email section to be a
1327 You can also either configure the method option in the email section to be a
1328 sendmail compatible mailer or fill out the [smtp] section so that the
1328 sendmail compatible mailer or fill out the [smtp] section so that the
1329 patchbomb extension can automatically send patchbombs directly from the
1329 patchbomb extension can automatically send patchbombs directly from the
1330 commandline. See the [email] and [smtp] sections in hgrc(5) for details.
1330 commandline. See the [email] and [smtp] sections in hgrc(5) for details.
1331
1331
1332 By default, 'hg email' will prompt for a "To" or "CC" header if you do not
1332 By default, 'hg email' will prompt for a "To" or "CC" header if you do not
1333 supply one via configuration or the command line. You can override this to
1333 supply one via configuration or the command line. You can override this to
1334 never prompt by configuring an empty value:
1334 never prompt by configuring an empty value:
1335
1335
1336 [email]
1336 [email]
1337 cc =
1337 cc =
1338
1338
1339 You can control the default inclusion of an introduction message with the
1339 You can control the default inclusion of an introduction message with the
1340 "patchbomb.intro" configuration option. The configuration is always
1340 "patchbomb.intro" configuration option. The configuration is always
1341 overwritten by command line flags like --intro and --desc:
1341 overwritten by command line flags like --intro and --desc:
1342
1342
1343 [patchbomb]
1343 [patchbomb]
1344 intro=auto # include introduction message if more than 1 patch (default)
1344 intro=auto # include introduction message if more than 1 patch (default)
1345 intro=never # never include an introduction message
1345 intro=never # never include an introduction message
1346 intro=always # always include an introduction message
1346 intro=always # always include an introduction message
1347
1347
1348 You can specify a template for flags to be added in subject prefixes. Flags
1348 You can specify a template for flags to be added in subject prefixes. Flags
1349 specified by --flag option are exported as "{flags}" keyword:
1349 specified by --flag option are exported as "{flags}" keyword:
1350
1350
1351 [patchbomb]
1351 [patchbomb]
1352 flagtemplate = "{separate(' ',
1352 flagtemplate = "{separate(' ',
1353 ifeq(branch, 'default', '', branch|upper),
1353 ifeq(branch, 'default', '', branch|upper),
1354 flags)}"
1354 flags)}"
1355
1355
1356 You can set patchbomb to always ask for confirmation by setting
1356 You can set patchbomb to always ask for confirmation by setting
1357 "patchbomb.confirm" to true.
1357 "patchbomb.confirm" to true.
1358
1358
1359 (use 'hg help extensions' for information on enabling extensions)
1359 (use 'hg help extensions' for information on enabling extensions)
1360
1360
1361
1361
1362 Broken disabled extension and command:
1362 Broken disabled extension and command:
1363
1363
1364 $ mkdir hgext
1364 $ mkdir hgext
1365 $ echo > hgext/__init__.py
1365 $ echo > hgext/__init__.py
1366 $ cat > hgext/broken.py <<NO_CHECK_EOF
1366 $ cat > hgext/broken.py <<NO_CHECK_EOF
1367 > "broken extension'
1367 > "broken extension'
1368 > NO_CHECK_EOF
1368 > NO_CHECK_EOF
1369 $ cat > path.py <<EOF
1369 $ cat > path.py <<EOF
1370 > import os
1370 > import os
1371 > import sys
1371 > import sys
1372 > sys.path.insert(0, os.environ['HGEXTPATH'])
1372 > sys.path.insert(0, os.environ['HGEXTPATH'])
1373 > EOF
1373 > EOF
1374 $ HGEXTPATH=`pwd`
1374 $ HGEXTPATH=`pwd`
1375 $ export HGEXTPATH
1375 $ export HGEXTPATH
1376
1376
1377 $ hg --config extensions.path=./path.py help broken
1377 $ hg --config extensions.path=./path.py help broken
1378 broken extension - (no help text available)
1378 broken extension - (no help text available)
1379
1379
1380 (use 'hg help extensions' for information on enabling extensions)
1380 (use 'hg help extensions' for information on enabling extensions)
1381
1381
1382
1382
1383 $ cat > hgext/forest.py <<EOF
1383 $ cat > hgext/forest.py <<EOF
1384 > cmdtable = None
1384 > cmdtable = None
1385 > @command()
1385 > @command()
1386 > def f():
1386 > def f():
1387 > pass
1387 > pass
1388 > @command(123)
1388 > @command(123)
1389 > def g():
1389 > def g():
1390 > pass
1390 > pass
1391 > EOF
1391 > EOF
1392 $ hg --config extensions.path=./path.py help foo
1392 $ hg --config extensions.path=./path.py help foo
1393 abort: no such help topic: foo
1393 abort: no such help topic: foo
1394 (try 'hg help --keyword foo')
1394 (try 'hg help --keyword foo')
1395 [255]
1395 [255]
1396
1396
1397 $ cat > throw.py <<EOF
1397 $ cat > throw.py <<EOF
1398 > from mercurial import commands, registrar, util
1398 > from mercurial import commands, registrar, util
1399 > cmdtable = {}
1399 > cmdtable = {}
1400 > command = registrar.command(cmdtable)
1400 > command = registrar.command(cmdtable)
1401 > class Bogon(Exception): pass
1401 > class Bogon(Exception): pass
1402 > # NB: version should be bytes; simulating extension not ported to py3
1402 > # NB: version should be bytes; simulating extension not ported to py3
1403 > __version__ = '1.0.0'
1403 > __version__ = '1.0.0'
1404 > @command(b'throw', [], b'hg throw', norepo=True)
1404 > @command(b'throw', [], b'hg throw', norepo=True)
1405 > def throw(ui, **opts):
1405 > def throw(ui, **opts):
1406 > """throws an exception"""
1406 > """throws an exception"""
1407 > raise Bogon()
1407 > raise Bogon()
1408 > EOF
1408 > EOF
1409
1409
1410 Test extension without proper byteification of key attributes doesn't crash when
1410 Test extension without proper byteification of key attributes doesn't crash when
1411 accessed.
1411 accessed.
1412
1412
1413 $ hg version -v --config extensions.throw=throw.py | grep '^ '
1413 $ hg version -v --config extensions.throw=throw.py | grep '^ '
1414 throw external 1.0.0
1414 throw external 1.0.0
1415
1415
1416 No declared supported version, extension complains:
1416 No declared supported version, extension complains:
1417 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1417 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1418 ** Unknown exception encountered with possibly-broken third-party extension throw
1418 ** Unknown exception encountered with possibly-broken third-party extension throw 1.0.0
1419 ** which supports versions unknown of Mercurial.
1419 ** which supports versions unknown of Mercurial.
1420 ** Please disable throw and try your action again.
1420 ** Please disable throw and try your action again.
1421 ** If that fixes the bug please report it to the extension author.
1421 ** If that fixes the bug please report it to the extension author.
1422 ** Python * (glob)
1422 ** Python * (glob)
1423 ** Mercurial Distributed SCM * (glob)
1423 ** Mercurial Distributed SCM * (glob)
1424 ** Extensions loaded: throw
1424 ** Extensions loaded: throw
1425
1425
1426 empty declaration of supported version, extension complains (but doesn't choke if
1426 empty declaration of supported version, extension complains (but doesn't choke if
1427 the value is improperly a str instead of bytes):
1427 the value is improperly a str instead of bytes):
1428 $ echo "testedwith = ''" >> throw.py
1428 $ echo "testedwith = ''" >> throw.py
1429 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1429 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1430 ** Unknown exception encountered with possibly-broken third-party extension throw
1430 ** Unknown exception encountered with possibly-broken third-party extension throw 1.0.0
1431 ** which supports versions unknown of Mercurial.
1431 ** which supports versions unknown of Mercurial.
1432 ** Please disable throw and try your action again.
1432 ** Please disable throw and try your action again.
1433 ** If that fixes the bug please report it to the extension author.
1433 ** If that fixes the bug please report it to the extension author.
1434 ** Python * (glob)
1434 ** Python * (glob)
1435 ** Mercurial Distributed SCM (*) (glob)
1435 ** Mercurial Distributed SCM (*) (glob)
1436 ** Extensions loaded: throw
1436 ** Extensions loaded: throw
1437
1437
1438 If the extension specifies a buglink, show that (but don't choke if the value is
1438 If the extension specifies a buglink, show that (but don't choke if the value is
1439 improperly a str instead of bytes):
1439 improperly a str instead of bytes):
1440 $ echo 'buglink = "http://example.com/bts"' >> throw.py
1440 $ echo 'buglink = "http://example.com/bts"' >> throw.py
1441 $ rm -f throw.pyc throw.pyo
1441 $ rm -f throw.pyc throw.pyo
1442 $ rm -Rf __pycache__
1442 $ rm -Rf __pycache__
1443 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1443 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1444 ** Unknown exception encountered with possibly-broken third-party extension throw
1444 ** Unknown exception encountered with possibly-broken third-party extension throw 1.0.0
1445 ** which supports versions unknown of Mercurial.
1445 ** which supports versions unknown of Mercurial.
1446 ** Please disable throw and try your action again.
1446 ** Please disable throw and try your action again.
1447 ** If that fixes the bug please report it to http://example.com/bts
1447 ** If that fixes the bug please report it to http://example.com/bts
1448 ** Python * (glob)
1448 ** Python * (glob)
1449 ** Mercurial Distributed SCM (*) (glob)
1449 ** Mercurial Distributed SCM (*) (glob)
1450 ** Extensions loaded: throw
1450 ** Extensions loaded: throw
1451
1451
1452 If the extensions declare outdated versions, accuse the older extension first:
1452 If the extensions declare outdated versions, accuse the older extension first:
1453 $ echo "from mercurial import util" >> older.py
1453 $ echo "from mercurial import util" >> older.py
1454 $ echo "util.version = lambda:b'2.2'" >> older.py
1454 $ echo "util.version = lambda:b'2.2'" >> older.py
1455 $ echo "testedwith = b'1.9.3'" >> older.py
1455 $ echo "testedwith = b'1.9.3'" >> older.py
1456 $ echo "testedwith = b'2.1.1'" >> throw.py
1456 $ echo "testedwith = b'2.1.1'" >> throw.py
1457 $ rm -f throw.pyc throw.pyo
1457 $ rm -f throw.pyc throw.pyo
1458 $ rm -Rf __pycache__
1458 $ rm -Rf __pycache__
1459 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1459 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1460 > throw 2>&1 | egrep '^\*\*'
1460 > throw 2>&1 | egrep '^\*\*'
1461 ** Unknown exception encountered with possibly-broken third-party extension older
1461 ** Unknown exception encountered with possibly-broken third-party extension older (version N/A)
1462 ** which supports versions 1.9 of Mercurial.
1462 ** which supports versions 1.9 of Mercurial.
1463 ** Please disable older and try your action again.
1463 ** Please disable older and try your action again.
1464 ** If that fixes the bug please report it to the extension author.
1464 ** If that fixes the bug please report it to the extension author.
1465 ** Python * (glob)
1465 ** Python * (glob)
1466 ** Mercurial Distributed SCM (version 2.2)
1466 ** Mercurial Distributed SCM (version 2.2)
1467 ** Extensions loaded: throw, older
1467 ** Extensions loaded: throw, older
1468
1468
1469 One extension only tested with older, one only with newer versions:
1469 One extension only tested with older, one only with newer versions:
1470 $ echo "util.version = lambda:b'2.1'" >> older.py
1470 $ echo "util.version = lambda:b'2.1'" >> older.py
1471 $ rm -f older.pyc older.pyo
1471 $ rm -f older.pyc older.pyo
1472 $ rm -Rf __pycache__
1472 $ rm -Rf __pycache__
1473 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1473 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1474 > throw 2>&1 | egrep '^\*\*'
1474 > throw 2>&1 | egrep '^\*\*'
1475 ** Unknown exception encountered with possibly-broken third-party extension older
1475 ** Unknown exception encountered with possibly-broken third-party extension older (version N/A)
1476 ** which supports versions 1.9 of Mercurial.
1476 ** which supports versions 1.9 of Mercurial.
1477 ** Please disable older and try your action again.
1477 ** Please disable older and try your action again.
1478 ** If that fixes the bug please report it to the extension author.
1478 ** If that fixes the bug please report it to the extension author.
1479 ** Python * (glob)
1479 ** Python * (glob)
1480 ** Mercurial Distributed SCM (version 2.1)
1480 ** Mercurial Distributed SCM (version 2.1)
1481 ** Extensions loaded: throw, older
1481 ** Extensions loaded: throw, older
1482
1482
1483 Older extension is tested with current version, the other only with newer:
1483 Older extension is tested with current version, the other only with newer:
1484 $ echo "util.version = lambda:b'1.9.3'" >> older.py
1484 $ echo "util.version = lambda:b'1.9.3'" >> older.py
1485 $ rm -f older.pyc older.pyo
1485 $ rm -f older.pyc older.pyo
1486 $ rm -Rf __pycache__
1486 $ rm -Rf __pycache__
1487 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1487 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1488 > throw 2>&1 | egrep '^\*\*'
1488 > throw 2>&1 | egrep '^\*\*'
1489 ** Unknown exception encountered with possibly-broken third-party extension throw
1489 ** Unknown exception encountered with possibly-broken third-party extension throw 1.0.0
1490 ** which supports versions 2.1 of Mercurial.
1490 ** which supports versions 2.1 of Mercurial.
1491 ** Please disable throw and try your action again.
1491 ** Please disable throw and try your action again.
1492 ** If that fixes the bug please report it to http://example.com/bts
1492 ** If that fixes the bug please report it to http://example.com/bts
1493 ** Python * (glob)
1493 ** Python * (glob)
1494 ** Mercurial Distributed SCM (version 1.9.3)
1494 ** Mercurial Distributed SCM (version 1.9.3)
1495 ** Extensions loaded: throw, older
1495 ** Extensions loaded: throw, older
1496
1496
1497 Ability to point to a different point
1497 Ability to point to a different point
1498 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1498 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1499 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
1499 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
1500 ** unknown exception encountered, please report by visiting
1500 ** unknown exception encountered, please report by visiting
1501 ** Your Local Goat Lenders
1501 ** Your Local Goat Lenders
1502 ** Python * (glob)
1502 ** Python * (glob)
1503 ** Mercurial Distributed SCM (*) (glob)
1503 ** Mercurial Distributed SCM (*) (glob)
1504 ** Extensions loaded: throw, older
1504 ** Extensions loaded: throw, older
1505
1505
1506 Declare the version as supporting this hg version, show regular bts link:
1506 Declare the version as supporting this hg version, show regular bts link:
1507 $ hgver=`hg debuginstall -T '{hgver}'`
1507 $ hgver=`hg debuginstall -T '{hgver}'`
1508 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
1508 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
1509 $ if [ -z "$hgver" ]; then
1509 $ if [ -z "$hgver" ]; then
1510 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
1510 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
1511 > fi
1511 > fi
1512 $ rm -f throw.pyc throw.pyo
1512 $ rm -f throw.pyc throw.pyo
1513 $ rm -Rf __pycache__
1513 $ rm -Rf __pycache__
1514 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1514 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1515 ** unknown exception encountered, please report by visiting
1515 ** unknown exception encountered, please report by visiting
1516 ** https://mercurial-scm.org/wiki/BugTracker
1516 ** https://mercurial-scm.org/wiki/BugTracker
1517 ** Python * (glob)
1517 ** Python * (glob)
1518 ** Mercurial Distributed SCM (*) (glob)
1518 ** Mercurial Distributed SCM (*) (glob)
1519 ** Extensions loaded: throw
1519 ** Extensions loaded: throw
1520
1520
1521 Patch version is ignored during compatibility check
1521 Patch version is ignored during compatibility check
1522 $ echo "testedwith = b'3.2'" >> throw.py
1522 $ echo "testedwith = b'3.2'" >> throw.py
1523 $ echo "util.version = lambda:b'3.2.2'" >> throw.py
1523 $ echo "util.version = lambda:b'3.2.2'" >> throw.py
1524 $ rm -f throw.pyc throw.pyo
1524 $ rm -f throw.pyc throw.pyo
1525 $ rm -Rf __pycache__
1525 $ rm -Rf __pycache__
1526 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1526 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1527 ** unknown exception encountered, please report by visiting
1527 ** unknown exception encountered, please report by visiting
1528 ** https://mercurial-scm.org/wiki/BugTracker
1528 ** https://mercurial-scm.org/wiki/BugTracker
1529 ** Python * (glob)
1529 ** Python * (glob)
1530 ** Mercurial Distributed SCM (*) (glob)
1530 ** Mercurial Distributed SCM (*) (glob)
1531 ** Extensions loaded: throw
1531 ** Extensions loaded: throw
1532
1532
1533 Test version number support in 'hg version':
1533 Test version number support in 'hg version':
1534 $ echo '__version__ = (1, 2, 3)' >> throw.py
1534 $ echo '__version__ = (1, 2, 3)' >> throw.py
1535 $ rm -f throw.pyc throw.pyo
1535 $ rm -f throw.pyc throw.pyo
1536 $ rm -Rf __pycache__
1536 $ rm -Rf __pycache__
1537 $ hg version -v
1537 $ hg version -v
1538 Mercurial Distributed SCM (version *) (glob)
1538 Mercurial Distributed SCM (version *) (glob)
1539 (see https://mercurial-scm.org for more information)
1539 (see https://mercurial-scm.org for more information)
1540
1540
1541 Copyright (C) 2005-* Matt Mackall and others (glob)
1541 Copyright (C) 2005-* Matt Mackall and others (glob)
1542 This is free software; see the source for copying conditions. There is NO
1542 This is free software; see the source for copying conditions. There is NO
1543 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1543 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1544
1544
1545 Enabled extensions:
1545 Enabled extensions:
1546
1546
1547
1547
1548 $ hg version -v --config extensions.throw=throw.py
1548 $ hg version -v --config extensions.throw=throw.py
1549 Mercurial Distributed SCM (version *) (glob)
1549 Mercurial Distributed SCM (version *) (glob)
1550 (see https://mercurial-scm.org for more information)
1550 (see https://mercurial-scm.org for more information)
1551
1551
1552 Copyright (C) 2005-* Matt Mackall and others (glob)
1552 Copyright (C) 2005-* Matt Mackall and others (glob)
1553 This is free software; see the source for copying conditions. There is NO
1553 This is free software; see the source for copying conditions. There is NO
1554 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1554 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1555
1555
1556 Enabled extensions:
1556 Enabled extensions:
1557
1557
1558 throw external 1.2.3
1558 throw external 1.2.3
1559 $ echo 'getversion = lambda: b"1.twentythree"' >> throw.py
1559 $ echo 'getversion = lambda: b"1.twentythree"' >> throw.py
1560 $ rm -f throw.pyc throw.pyo
1560 $ rm -f throw.pyc throw.pyo
1561 $ rm -Rf __pycache__
1561 $ rm -Rf __pycache__
1562 $ hg version -v --config extensions.throw=throw.py --config extensions.strip=
1562 $ hg version -v --config extensions.throw=throw.py --config extensions.strip=
1563 Mercurial Distributed SCM (version *) (glob)
1563 Mercurial Distributed SCM (version *) (glob)
1564 (see https://mercurial-scm.org for more information)
1564 (see https://mercurial-scm.org for more information)
1565
1565
1566 Copyright (C) 2005-* Matt Mackall and others (glob)
1566 Copyright (C) 2005-* Matt Mackall and others (glob)
1567 This is free software; see the source for copying conditions. There is NO
1567 This is free software; see the source for copying conditions. There is NO
1568 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1568 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1569
1569
1570 Enabled extensions:
1570 Enabled extensions:
1571
1571
1572 strip internal
1572 strip internal
1573 throw external 1.twentythree
1573 throw external 1.twentythree
1574
1574
1575 $ hg version -q --config extensions.throw=throw.py
1575 $ hg version -q --config extensions.throw=throw.py
1576 Mercurial Distributed SCM (version *) (glob)
1576 Mercurial Distributed SCM (version *) (glob)
1577
1577
1578 Test template output:
1578 Test template output:
1579
1579
1580 $ hg version --config extensions.strip= -T'{extensions}'
1580 $ hg version --config extensions.strip= -T'{extensions}'
1581 strip
1581 strip
1582
1582
1583 Test JSON output of version:
1583 Test JSON output of version:
1584
1584
1585 $ hg version -Tjson
1585 $ hg version -Tjson
1586 [
1586 [
1587 {
1587 {
1588 "extensions": [],
1588 "extensions": [],
1589 "ver": "*" (glob)
1589 "ver": "*" (glob)
1590 }
1590 }
1591 ]
1591 ]
1592
1592
1593 $ hg version --config extensions.throw=throw.py -Tjson
1593 $ hg version --config extensions.throw=throw.py -Tjson
1594 [
1594 [
1595 {
1595 {
1596 "extensions": [{"bundled": false, "name": "throw", "ver": "1.twentythree"}],
1596 "extensions": [{"bundled": false, "name": "throw", "ver": "1.twentythree"}],
1597 "ver": "3.2.2"
1597 "ver": "3.2.2"
1598 }
1598 }
1599 ]
1599 ]
1600
1600
1601 $ hg version --config extensions.strip= -Tjson
1601 $ hg version --config extensions.strip= -Tjson
1602 [
1602 [
1603 {
1603 {
1604 "extensions": [{"bundled": true, "name": "strip", "ver": null}],
1604 "extensions": [{"bundled": true, "name": "strip", "ver": null}],
1605 "ver": "*" (glob)
1605 "ver": "*" (glob)
1606 }
1606 }
1607 ]
1607 ]
1608
1608
1609 Test template output of version:
1609 Test template output of version:
1610
1610
1611 $ hg version --config extensions.throw=throw.py --config extensions.strip= \
1611 $ hg version --config extensions.throw=throw.py --config extensions.strip= \
1612 > -T'{extensions % "{name} {pad(ver, 16)} ({if(bundled, "internal", "external")})\n"}'
1612 > -T'{extensions % "{name} {pad(ver, 16)} ({if(bundled, "internal", "external")})\n"}'
1613 strip (internal)
1613 strip (internal)
1614 throw 1.twentythree (external)
1614 throw 1.twentythree (external)
1615
1615
1616 Refuse to load extensions with minimum version requirements
1616 Refuse to load extensions with minimum version requirements
1617
1617
1618 $ cat > minversion1.py << EOF
1618 $ cat > minversion1.py << EOF
1619 > from mercurial import util
1619 > from mercurial import util
1620 > util.version = lambda: b'3.5.2'
1620 > util.version = lambda: b'3.5.2'
1621 > minimumhgversion = b'3.6'
1621 > minimumhgversion = b'3.6'
1622 > EOF
1622 > EOF
1623 $ hg --config extensions.minversion=minversion1.py version
1623 $ hg --config extensions.minversion=minversion1.py version
1624 (third party extension minversion requires version 3.6 or newer of Mercurial (current: 3.5.2); disabling)
1624 (third party extension minversion requires version 3.6 or newer of Mercurial (current: 3.5.2); disabling)
1625 Mercurial Distributed SCM (version 3.5.2)
1625 Mercurial Distributed SCM (version 3.5.2)
1626 (see https://mercurial-scm.org for more information)
1626 (see https://mercurial-scm.org for more information)
1627
1627
1628 Copyright (C) 2005-* Matt Mackall and others (glob)
1628 Copyright (C) 2005-* Matt Mackall and others (glob)
1629 This is free software; see the source for copying conditions. There is NO
1629 This is free software; see the source for copying conditions. There is NO
1630 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1630 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1631
1631
1632 $ cat > minversion2.py << EOF
1632 $ cat > minversion2.py << EOF
1633 > from mercurial import util
1633 > from mercurial import util
1634 > util.version = lambda: b'3.6'
1634 > util.version = lambda: b'3.6'
1635 > minimumhgversion = b'3.7'
1635 > minimumhgversion = b'3.7'
1636 > EOF
1636 > EOF
1637 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1637 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1638 (third party extension minversion requires version 3.7 or newer of Mercurial (current: 3.6); disabling)
1638 (third party extension minversion requires version 3.7 or newer of Mercurial (current: 3.6); disabling)
1639
1639
1640 Can load version that is only off by point release
1640 Can load version that is only off by point release
1641
1641
1642 $ cat > minversion2.py << EOF
1642 $ cat > minversion2.py << EOF
1643 > from mercurial import util
1643 > from mercurial import util
1644 > util.version = lambda: b'3.6.1'
1644 > util.version = lambda: b'3.6.1'
1645 > minimumhgversion = b'3.6'
1645 > minimumhgversion = b'3.6'
1646 > EOF
1646 > EOF
1647 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1647 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1648 [1]
1648 [1]
1649
1649
1650 Can load minimum version identical to current
1650 Can load minimum version identical to current
1651
1651
1652 $ cat > minversion3.py << EOF
1652 $ cat > minversion3.py << EOF
1653 > from mercurial import util
1653 > from mercurial import util
1654 > util.version = lambda: b'3.5'
1654 > util.version = lambda: b'3.5'
1655 > minimumhgversion = b'3.5'
1655 > minimumhgversion = b'3.5'
1656 > EOF
1656 > EOF
1657 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1657 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1658 [1]
1658 [1]
1659
1659
1660 Restore HGRCPATH
1660 Restore HGRCPATH
1661
1661
1662 $ HGRCPATH=$ORGHGRCPATH
1662 $ HGRCPATH=$ORGHGRCPATH
1663 $ export HGRCPATH
1663 $ export HGRCPATH
1664
1664
1665 Commands handling multiple repositories at a time should invoke only
1665 Commands handling multiple repositories at a time should invoke only
1666 "reposetup()" of extensions enabling in the target repository.
1666 "reposetup()" of extensions enabling in the target repository.
1667
1667
1668 $ mkdir reposetup-test
1668 $ mkdir reposetup-test
1669 $ cd reposetup-test
1669 $ cd reposetup-test
1670
1670
1671 $ cat > $TESTTMP/reposetuptest.py <<EOF
1671 $ cat > $TESTTMP/reposetuptest.py <<EOF
1672 > from mercurial import extensions
1672 > from mercurial import extensions
1673 > def reposetup(ui, repo):
1673 > def reposetup(ui, repo):
1674 > ui.write(b'reposetup() for %s\n' % (repo.root))
1674 > ui.write(b'reposetup() for %s\n' % (repo.root))
1675 > ui.flush()
1675 > ui.flush()
1676 > EOF
1676 > EOF
1677 $ hg init src
1677 $ hg init src
1678 $ echo a > src/a
1678 $ echo a > src/a
1679 $ hg -R src commit -Am '#0 at src/a'
1679 $ hg -R src commit -Am '#0 at src/a'
1680 adding a
1680 adding a
1681 $ echo '[extensions]' >> src/.hg/hgrc
1681 $ echo '[extensions]' >> src/.hg/hgrc
1682 $ echo '# enable extension locally' >> src/.hg/hgrc
1682 $ echo '# enable extension locally' >> src/.hg/hgrc
1683 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1683 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1684 $ hg -R src status
1684 $ hg -R src status
1685 reposetup() for $TESTTMP/reposetup-test/src
1685 reposetup() for $TESTTMP/reposetup-test/src
1686 reposetup() for $TESTTMP/reposetup-test/src (chg !)
1686 reposetup() for $TESTTMP/reposetup-test/src (chg !)
1687
1687
1688 #if no-extraextensions
1688 #if no-extraextensions
1689 $ hg --cwd src debugextensions
1689 $ hg --cwd src debugextensions
1690 reposetup() for $TESTTMP/reposetup-test/src
1690 reposetup() for $TESTTMP/reposetup-test/src
1691 dodo (untested!)
1691 dodo (untested!)
1692 dudu (untested!)
1692 dudu (untested!)
1693 mq
1693 mq
1694 reposetuptest (untested!)
1694 reposetuptest (untested!)
1695 strip
1695 strip
1696 #endif
1696 #endif
1697
1697
1698 $ hg clone -U src clone-dst1
1698 $ hg clone -U src clone-dst1
1699 reposetup() for $TESTTMP/reposetup-test/src
1699 reposetup() for $TESTTMP/reposetup-test/src
1700 $ hg init push-dst1
1700 $ hg init push-dst1
1701 $ hg -q -R src push push-dst1
1701 $ hg -q -R src push push-dst1
1702 reposetup() for $TESTTMP/reposetup-test/src
1702 reposetup() for $TESTTMP/reposetup-test/src
1703 $ hg init pull-src1
1703 $ hg init pull-src1
1704 $ hg -q -R pull-src1 pull src
1704 $ hg -q -R pull-src1 pull src
1705 reposetup() for $TESTTMP/reposetup-test/src
1705 reposetup() for $TESTTMP/reposetup-test/src
1706
1706
1707 $ cat <<EOF >> $HGRCPATH
1707 $ cat <<EOF >> $HGRCPATH
1708 > [extensions]
1708 > [extensions]
1709 > # disable extension globally and explicitly
1709 > # disable extension globally and explicitly
1710 > reposetuptest = !
1710 > reposetuptest = !
1711 > EOF
1711 > EOF
1712 $ hg clone -U src clone-dst2
1712 $ hg clone -U src clone-dst2
1713 reposetup() for $TESTTMP/reposetup-test/src
1713 reposetup() for $TESTTMP/reposetup-test/src
1714 $ hg init push-dst2
1714 $ hg init push-dst2
1715 $ hg -q -R src push push-dst2
1715 $ hg -q -R src push push-dst2
1716 reposetup() for $TESTTMP/reposetup-test/src
1716 reposetup() for $TESTTMP/reposetup-test/src
1717 $ hg init pull-src2
1717 $ hg init pull-src2
1718 $ hg -q -R pull-src2 pull src
1718 $ hg -q -R pull-src2 pull src
1719 reposetup() for $TESTTMP/reposetup-test/src
1719 reposetup() for $TESTTMP/reposetup-test/src
1720
1720
1721 $ cat <<EOF >> $HGRCPATH
1721 $ cat <<EOF >> $HGRCPATH
1722 > [extensions]
1722 > [extensions]
1723 > # enable extension globally
1723 > # enable extension globally
1724 > reposetuptest = $TESTTMP/reposetuptest.py
1724 > reposetuptest = $TESTTMP/reposetuptest.py
1725 > EOF
1725 > EOF
1726 $ hg clone -U src clone-dst3
1726 $ hg clone -U src clone-dst3
1727 reposetup() for $TESTTMP/reposetup-test/src
1727 reposetup() for $TESTTMP/reposetup-test/src
1728 reposetup() for $TESTTMP/reposetup-test/clone-dst3
1728 reposetup() for $TESTTMP/reposetup-test/clone-dst3
1729 $ hg init push-dst3
1729 $ hg init push-dst3
1730 reposetup() for $TESTTMP/reposetup-test/push-dst3
1730 reposetup() for $TESTTMP/reposetup-test/push-dst3
1731 $ hg -q -R src push push-dst3
1731 $ hg -q -R src push push-dst3
1732 reposetup() for $TESTTMP/reposetup-test/src
1732 reposetup() for $TESTTMP/reposetup-test/src
1733 reposetup() for $TESTTMP/reposetup-test/push-dst3
1733 reposetup() for $TESTTMP/reposetup-test/push-dst3
1734 $ hg init pull-src3
1734 $ hg init pull-src3
1735 reposetup() for $TESTTMP/reposetup-test/pull-src3
1735 reposetup() for $TESTTMP/reposetup-test/pull-src3
1736 $ hg -q -R pull-src3 pull src
1736 $ hg -q -R pull-src3 pull src
1737 reposetup() for $TESTTMP/reposetup-test/pull-src3
1737 reposetup() for $TESTTMP/reposetup-test/pull-src3
1738 reposetup() for $TESTTMP/reposetup-test/src
1738 reposetup() for $TESTTMP/reposetup-test/src
1739
1739
1740 $ echo '[extensions]' >> src/.hg/hgrc
1740 $ echo '[extensions]' >> src/.hg/hgrc
1741 $ echo '# disable extension locally' >> src/.hg/hgrc
1741 $ echo '# disable extension locally' >> src/.hg/hgrc
1742 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1742 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1743 $ hg clone -U src clone-dst4
1743 $ hg clone -U src clone-dst4
1744 reposetup() for $TESTTMP/reposetup-test/clone-dst4
1744 reposetup() for $TESTTMP/reposetup-test/clone-dst4
1745 $ hg init push-dst4
1745 $ hg init push-dst4
1746 reposetup() for $TESTTMP/reposetup-test/push-dst4
1746 reposetup() for $TESTTMP/reposetup-test/push-dst4
1747 $ hg -q -R src push push-dst4
1747 $ hg -q -R src push push-dst4
1748 reposetup() for $TESTTMP/reposetup-test/push-dst4
1748 reposetup() for $TESTTMP/reposetup-test/push-dst4
1749 $ hg init pull-src4
1749 $ hg init pull-src4
1750 reposetup() for $TESTTMP/reposetup-test/pull-src4
1750 reposetup() for $TESTTMP/reposetup-test/pull-src4
1751 $ hg -q -R pull-src4 pull src
1751 $ hg -q -R pull-src4 pull src
1752 reposetup() for $TESTTMP/reposetup-test/pull-src4
1752 reposetup() for $TESTTMP/reposetup-test/pull-src4
1753
1753
1754 disabling in command line overlays with all configuration
1754 disabling in command line overlays with all configuration
1755 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1755 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1756 $ hg --config extensions.reposetuptest=! init push-dst5
1756 $ hg --config extensions.reposetuptest=! init push-dst5
1757 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1757 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1758 $ hg --config extensions.reposetuptest=! init pull-src5
1758 $ hg --config extensions.reposetuptest=! init pull-src5
1759 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1759 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1760
1760
1761 $ cat <<EOF >> $HGRCPATH
1761 $ cat <<EOF >> $HGRCPATH
1762 > [extensions]
1762 > [extensions]
1763 > # disable extension globally and explicitly
1763 > # disable extension globally and explicitly
1764 > reposetuptest = !
1764 > reposetuptest = !
1765 > EOF
1765 > EOF
1766 $ hg init parent
1766 $ hg init parent
1767 $ hg init parent/sub1
1767 $ hg init parent/sub1
1768 $ echo 1 > parent/sub1/1
1768 $ echo 1 > parent/sub1/1
1769 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1769 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1770 adding 1
1770 adding 1
1771 $ hg init parent/sub2
1771 $ hg init parent/sub2
1772 $ hg init parent/sub2/sub21
1772 $ hg init parent/sub2/sub21
1773 $ echo 21 > parent/sub2/sub21/21
1773 $ echo 21 > parent/sub2/sub21/21
1774 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1774 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1775 adding 21
1775 adding 21
1776 $ cat > parent/sub2/.hgsub <<EOF
1776 $ cat > parent/sub2/.hgsub <<EOF
1777 > sub21 = sub21
1777 > sub21 = sub21
1778 > EOF
1778 > EOF
1779 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1779 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1780 adding .hgsub
1780 adding .hgsub
1781 $ hg init parent/sub3
1781 $ hg init parent/sub3
1782 $ echo 3 > parent/sub3/3
1782 $ echo 3 > parent/sub3/3
1783 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1783 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1784 adding 3
1784 adding 3
1785 $ cat > parent/.hgsub <<EOF
1785 $ cat > parent/.hgsub <<EOF
1786 > sub1 = sub1
1786 > sub1 = sub1
1787 > sub2 = sub2
1787 > sub2 = sub2
1788 > sub3 = sub3
1788 > sub3 = sub3
1789 > EOF
1789 > EOF
1790 $ hg -R parent commit -Am '#0 at parent'
1790 $ hg -R parent commit -Am '#0 at parent'
1791 adding .hgsub
1791 adding .hgsub
1792 $ echo '[extensions]' >> parent/.hg/hgrc
1792 $ echo '[extensions]' >> parent/.hg/hgrc
1793 $ echo '# enable extension locally' >> parent/.hg/hgrc
1793 $ echo '# enable extension locally' >> parent/.hg/hgrc
1794 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1794 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1795 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1795 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1796 $ hg -R parent status -S -A
1796 $ hg -R parent status -S -A
1797 reposetup() for $TESTTMP/reposetup-test/parent
1797 reposetup() for $TESTTMP/reposetup-test/parent
1798 reposetup() for $TESTTMP/reposetup-test/parent/sub2
1798 reposetup() for $TESTTMP/reposetup-test/parent/sub2
1799 C .hgsub
1799 C .hgsub
1800 C .hgsubstate
1800 C .hgsubstate
1801 C sub1/1
1801 C sub1/1
1802 C sub2/.hgsub
1802 C sub2/.hgsub
1803 C sub2/.hgsubstate
1803 C sub2/.hgsubstate
1804 C sub2/sub21/21
1804 C sub2/sub21/21
1805 C sub3/3
1805 C sub3/3
1806
1806
1807 $ cd ..
1807 $ cd ..
1808
1808
1809 Prohibit registration of commands that don't use @command (issue5137)
1809 Prohibit registration of commands that don't use @command (issue5137)
1810
1810
1811 $ hg init deprecated
1811 $ hg init deprecated
1812 $ cd deprecated
1812 $ cd deprecated
1813
1813
1814 $ cat <<EOF > deprecatedcmd.py
1814 $ cat <<EOF > deprecatedcmd.py
1815 > def deprecatedcmd(repo, ui):
1815 > def deprecatedcmd(repo, ui):
1816 > pass
1816 > pass
1817 > cmdtable = {
1817 > cmdtable = {
1818 > b'deprecatedcmd': (deprecatedcmd, [], b''),
1818 > b'deprecatedcmd': (deprecatedcmd, [], b''),
1819 > }
1819 > }
1820 > EOF
1820 > EOF
1821 $ cat <<EOF > .hg/hgrc
1821 $ cat <<EOF > .hg/hgrc
1822 > [extensions]
1822 > [extensions]
1823 > deprecatedcmd = `pwd`/deprecatedcmd.py
1823 > deprecatedcmd = `pwd`/deprecatedcmd.py
1824 > mq = !
1824 > mq = !
1825 > hgext.mq = !
1825 > hgext.mq = !
1826 > hgext/mq = !
1826 > hgext/mq = !
1827 > EOF
1827 > EOF
1828
1828
1829 $ hg deprecatedcmd > /dev/null
1829 $ hg deprecatedcmd > /dev/null
1830 *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo
1830 *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo
1831 *** (use @command decorator to register 'deprecatedcmd')
1831 *** (use @command decorator to register 'deprecatedcmd')
1832 hg: unknown command 'deprecatedcmd'
1832 hg: unknown command 'deprecatedcmd'
1833 (use 'hg help' for a list of commands)
1833 (use 'hg help' for a list of commands)
1834 [255]
1834 [255]
1835
1835
1836 the extension shouldn't be loaded at all so the mq works:
1836 the extension shouldn't be loaded at all so the mq works:
1837
1837
1838 $ hg qseries --config extensions.mq= > /dev/null
1838 $ hg qseries --config extensions.mq= > /dev/null
1839 *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo
1839 *** failed to import extension deprecatedcmd from $TESTTMP/deprecated/deprecatedcmd.py: missing attributes: norepo, optionalrepo, inferrepo
1840 *** (use @command decorator to register 'deprecatedcmd')
1840 *** (use @command decorator to register 'deprecatedcmd')
1841
1841
1842 $ cd ..
1842 $ cd ..
1843
1843
1844 Test synopsis and docstring extending
1844 Test synopsis and docstring extending
1845
1845
1846 $ hg init exthelp
1846 $ hg init exthelp
1847 $ cat > exthelp.py <<EOF
1847 $ cat > exthelp.py <<EOF
1848 > from mercurial import commands, extensions
1848 > from mercurial import commands, extensions
1849 > def exbookmarks(orig, *args, **opts):
1849 > def exbookmarks(orig, *args, **opts):
1850 > return orig(*args, **opts)
1850 > return orig(*args, **opts)
1851 > def uisetup(ui):
1851 > def uisetup(ui):
1852 > synopsis = b' GREPME [--foo] [-x]'
1852 > synopsis = b' GREPME [--foo] [-x]'
1853 > docstring = '''
1853 > docstring = '''
1854 > GREPME make sure that this is in the help!
1854 > GREPME make sure that this is in the help!
1855 > '''
1855 > '''
1856 > extensions.wrapcommand(commands.table, b'bookmarks', exbookmarks,
1856 > extensions.wrapcommand(commands.table, b'bookmarks', exbookmarks,
1857 > synopsis, docstring)
1857 > synopsis, docstring)
1858 > EOF
1858 > EOF
1859 $ abspath=`pwd`/exthelp.py
1859 $ abspath=`pwd`/exthelp.py
1860 $ echo '[extensions]' >> $HGRCPATH
1860 $ echo '[extensions]' >> $HGRCPATH
1861 $ echo "exthelp = $abspath" >> $HGRCPATH
1861 $ echo "exthelp = $abspath" >> $HGRCPATH
1862 $ cd exthelp
1862 $ cd exthelp
1863 $ hg help bookmarks | grep GREPME
1863 $ hg help bookmarks | grep GREPME
1864 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1864 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1865 GREPME make sure that this is in the help!
1865 GREPME make sure that this is in the help!
1866 $ cd ..
1866 $ cd ..
1867
1867
1868 Prohibit the use of unicode strings as the default value of options
1868 Prohibit the use of unicode strings as the default value of options
1869
1869
1870 $ hg init $TESTTMP/opt-unicode-default
1870 $ hg init $TESTTMP/opt-unicode-default
1871
1871
1872 $ cat > $TESTTMP/test_unicode_default_value.py << EOF
1872 $ cat > $TESTTMP/test_unicode_default_value.py << EOF
1873 > from __future__ import print_function
1873 > from __future__ import print_function
1874 > from mercurial import registrar
1874 > from mercurial import registrar
1875 > cmdtable = {}
1875 > cmdtable = {}
1876 > command = registrar.command(cmdtable)
1876 > command = registrar.command(cmdtable)
1877 > @command(b'dummy', [(b'', b'opt', u'value', u'help')], 'ext [OPTIONS]')
1877 > @command(b'dummy', [(b'', b'opt', u'value', u'help')], 'ext [OPTIONS]')
1878 > def ext(*args, **opts):
1878 > def ext(*args, **opts):
1879 > print(opts[b'opt'], flush=True)
1879 > print(opts[b'opt'], flush=True)
1880 > EOF
1880 > EOF
1881 $ "$PYTHON" $TESTTMP/unflush.py $TESTTMP/test_unicode_default_value.py
1881 $ "$PYTHON" $TESTTMP/unflush.py $TESTTMP/test_unicode_default_value.py
1882 $ cat > $TESTTMP/opt-unicode-default/.hg/hgrc << EOF
1882 $ cat > $TESTTMP/opt-unicode-default/.hg/hgrc << EOF
1883 > [extensions]
1883 > [extensions]
1884 > test_unicode_default_value = $TESTTMP/test_unicode_default_value.py
1884 > test_unicode_default_value = $TESTTMP/test_unicode_default_value.py
1885 > EOF
1885 > EOF
1886 $ hg -R $TESTTMP/opt-unicode-default dummy
1886 $ hg -R $TESTTMP/opt-unicode-default dummy
1887 *** failed to import extension test_unicode_default_value from $TESTTMP/test_unicode_default_value.py: unicode *'value' found in cmdtable.dummy (glob)
1887 *** failed to import extension test_unicode_default_value from $TESTTMP/test_unicode_default_value.py: unicode *'value' found in cmdtable.dummy (glob)
1888 *** (use b'' to make it byte string)
1888 *** (use b'' to make it byte string)
1889 hg: unknown command 'dummy'
1889 hg: unknown command 'dummy'
1890 (did you mean summary?)
1890 (did you mean summary?)
1891 [255]
1891 [255]
General Comments 0
You need to be logged in to leave comments. Login now