##// END OF EJS Templates
errors: raise ConfigError on bad alias definition...
Martin von Zweigbergk -
r46524:35ab6e39 default
parent child Browse files
Show More
@@ -1,1324 +1,1324 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.Abort(_(b'too few arguments for command alias'))
513 raise error.Abort(_(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 ) % (self.name, cmd,)
633 ) % (self.name, cmd,)
634 self.unknowncmd = True
634 self.unknowncmd = True
635 except error.AmbiguousCommand:
635 except error.AmbiguousCommand:
636 self.badalias = _(
636 self.badalias = _(
637 b"alias '%s' resolves to ambiguous command '%s'"
637 b"alias '%s' resolves to ambiguous command '%s'"
638 ) % (self.name, cmd,)
638 ) % (self.name, cmd,)
639
639
640 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
640 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
641 # confine strings to be passed to i18n.gettext()
641 # confine strings to be passed to i18n.gettext()
642 cfg = {}
642 cfg = {}
643 for k in (b'doc', b'help', b'category'):
643 for k in (b'doc', b'help', b'category'):
644 v = ui.config(b'alias', b'%s:%s' % (name, k), None)
644 v = ui.config(b'alias', b'%s:%s' % (name, k), None)
645 if v is None:
645 if v is None:
646 continue
646 continue
647 if not encoding.isasciistr(v):
647 if not encoding.isasciistr(v):
648 self.badalias = _(
648 self.badalias = _(
649 b"non-ASCII character in alias definition '%s:%s'"
649 b"non-ASCII character in alias definition '%s:%s'"
650 ) % (name, k)
650 ) % (name, k)
651 return
651 return
652 cfg[k] = v
652 cfg[k] = v
653
653
654 self.help = cfg.get(b'help', defaulthelp or b'')
654 self.help = cfg.get(b'help', defaulthelp or b'')
655 if self.help and self.help.startswith(b"hg " + cmd):
655 if self.help and self.help.startswith(b"hg " + cmd):
656 # drop prefix in old-style help lines so hg shows the alias
656 # drop prefix in old-style help lines so hg shows the alias
657 self.help = self.help[4 + len(cmd) :]
657 self.help = self.help[4 + len(cmd) :]
658
658
659 self.owndoc = b'doc' in cfg
659 self.owndoc = b'doc' in cfg
660 doc = cfg.get(b'doc', pycompat.getdoc(fn))
660 doc = cfg.get(b'doc', pycompat.getdoc(fn))
661 if doc is not None:
661 if doc is not None:
662 doc = pycompat.sysstr(doc)
662 doc = pycompat.sysstr(doc)
663 self.__doc__ = doc
663 self.__doc__ = doc
664
664
665 self.helpcategory = cfg.get(
665 self.helpcategory = cfg.get(
666 b'category', registrar.command.CATEGORY_NONE
666 b'category', registrar.command.CATEGORY_NONE
667 )
667 )
668
668
669 @property
669 @property
670 def args(self):
670 def args(self):
671 args = pycompat.maplist(util.expandpath, self.givenargs)
671 args = pycompat.maplist(util.expandpath, self.givenargs)
672 return aliasargs(self.fn, args)
672 return aliasargs(self.fn, args)
673
673
674 def __getattr__(self, name):
674 def __getattr__(self, name):
675 adefaults = {
675 adefaults = {
676 'norepo': True,
676 'norepo': True,
677 'intents': set(),
677 'intents': set(),
678 'optionalrepo': False,
678 'optionalrepo': False,
679 'inferrepo': False,
679 'inferrepo': False,
680 }
680 }
681 if name not in adefaults:
681 if name not in adefaults:
682 raise AttributeError(name)
682 raise AttributeError(name)
683 if self.badalias or util.safehasattr(self, b'shell'):
683 if self.badalias or util.safehasattr(self, b'shell'):
684 return adefaults[name]
684 return adefaults[name]
685 return getattr(self.fn, name)
685 return getattr(self.fn, name)
686
686
687 def __call__(self, ui, *args, **opts):
687 def __call__(self, ui, *args, **opts):
688 if self.badalias:
688 if self.badalias:
689 hint = None
689 hint = None
690 if self.unknowncmd:
690 if self.unknowncmd:
691 try:
691 try:
692 # check if the command is in a disabled extension
692 # check if the command is in a disabled extension
693 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
693 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
694 hint = _(b"'%s' is provided by '%s' extension") % (cmd, ext)
694 hint = _(b"'%s' is provided by '%s' extension") % (cmd, ext)
695 except error.UnknownCommand:
695 except error.UnknownCommand:
696 pass
696 pass
697 raise error.Abort(self.badalias, hint=hint)
697 raise error.ConfigError(self.badalias, hint=hint)
698 if self.shadows:
698 if self.shadows:
699 ui.debug(
699 ui.debug(
700 b"alias '%s' shadows command '%s'\n" % (self.name, self.cmdname)
700 b"alias '%s' shadows command '%s'\n" % (self.name, self.cmdname)
701 )
701 )
702
702
703 ui.log(
703 ui.log(
704 b'commandalias',
704 b'commandalias',
705 b"alias '%s' expands to '%s'\n",
705 b"alias '%s' expands to '%s'\n",
706 self.name,
706 self.name,
707 self.definition,
707 self.definition,
708 )
708 )
709 if util.safehasattr(self, b'shell'):
709 if util.safehasattr(self, b'shell'):
710 return self.fn(ui, *args, **opts)
710 return self.fn(ui, *args, **opts)
711 else:
711 else:
712 try:
712 try:
713 return util.checksignature(self.fn)(ui, *args, **opts)
713 return util.checksignature(self.fn)(ui, *args, **opts)
714 except error.SignatureError:
714 except error.SignatureError:
715 args = b' '.join([self.cmdname] + self.args)
715 args = b' '.join([self.cmdname] + self.args)
716 ui.debug(b"alias '%s' expands to '%s'\n" % (self.name, args))
716 ui.debug(b"alias '%s' expands to '%s'\n" % (self.name, args))
717 raise
717 raise
718
718
719
719
720 class lazyaliasentry(object):
720 class lazyaliasentry(object):
721 """like a typical command entry (func, opts, help), but is lazy"""
721 """like a typical command entry (func, opts, help), but is lazy"""
722
722
723 def __init__(self, ui, name, definition, cmdtable, source):
723 def __init__(self, ui, name, definition, cmdtable, source):
724 self.ui = ui
724 self.ui = ui
725 self.name = name
725 self.name = name
726 self.definition = definition
726 self.definition = definition
727 self.cmdtable = cmdtable.copy()
727 self.cmdtable = cmdtable.copy()
728 self.source = source
728 self.source = source
729 self.alias = True
729 self.alias = True
730
730
731 @util.propertycache
731 @util.propertycache
732 def _aliasdef(self):
732 def _aliasdef(self):
733 return cmdalias(
733 return cmdalias(
734 self.ui, self.name, self.definition, self.cmdtable, self.source
734 self.ui, self.name, self.definition, self.cmdtable, self.source
735 )
735 )
736
736
737 def __getitem__(self, n):
737 def __getitem__(self, n):
738 aliasdef = self._aliasdef
738 aliasdef = self._aliasdef
739 if n == 0:
739 if n == 0:
740 return aliasdef
740 return aliasdef
741 elif n == 1:
741 elif n == 1:
742 return aliasdef.opts
742 return aliasdef.opts
743 elif n == 2:
743 elif n == 2:
744 return aliasdef.help
744 return aliasdef.help
745 else:
745 else:
746 raise IndexError
746 raise IndexError
747
747
748 def __iter__(self):
748 def __iter__(self):
749 for i in range(3):
749 for i in range(3):
750 yield self[i]
750 yield self[i]
751
751
752 def __len__(self):
752 def __len__(self):
753 return 3
753 return 3
754
754
755
755
756 def addaliases(ui, cmdtable):
756 def addaliases(ui, cmdtable):
757 # aliases are processed after extensions have been loaded, so they
757 # aliases are processed after extensions have been loaded, so they
758 # may use extension commands. Aliases can also use other alias definitions,
758 # may use extension commands. Aliases can also use other alias definitions,
759 # but only if they have been defined prior to the current definition.
759 # but only if they have been defined prior to the current definition.
760 for alias, definition in ui.configitems(b'alias', ignoresub=True):
760 for alias, definition in ui.configitems(b'alias', ignoresub=True):
761 try:
761 try:
762 if cmdtable[alias].definition == definition:
762 if cmdtable[alias].definition == definition:
763 continue
763 continue
764 except (KeyError, AttributeError):
764 except (KeyError, AttributeError):
765 # definition might not exist or it might not be a cmdalias
765 # definition might not exist or it might not be a cmdalias
766 pass
766 pass
767
767
768 source = ui.configsource(b'alias', alias)
768 source = ui.configsource(b'alias', alias)
769 entry = lazyaliasentry(ui, alias, definition, cmdtable, source)
769 entry = lazyaliasentry(ui, alias, definition, cmdtable, source)
770 cmdtable[alias] = entry
770 cmdtable[alias] = entry
771
771
772
772
773 def _parse(ui, args):
773 def _parse(ui, args):
774 options = {}
774 options = {}
775 cmdoptions = {}
775 cmdoptions = {}
776
776
777 try:
777 try:
778 args = fancyopts.fancyopts(args, commands.globalopts, options)
778 args = fancyopts.fancyopts(args, commands.globalopts, options)
779 except getopt.GetoptError as inst:
779 except getopt.GetoptError as inst:
780 raise error.CommandError(None, stringutil.forcebytestr(inst))
780 raise error.CommandError(None, stringutil.forcebytestr(inst))
781
781
782 if args:
782 if args:
783 cmd, args = args[0], args[1:]
783 cmd, args = args[0], args[1:]
784 aliases, entry = cmdutil.findcmd(
784 aliases, entry = cmdutil.findcmd(
785 cmd, commands.table, ui.configbool(b"ui", b"strict")
785 cmd, commands.table, ui.configbool(b"ui", b"strict")
786 )
786 )
787 cmd = aliases[0]
787 cmd = aliases[0]
788 args = aliasargs(entry[0], args)
788 args = aliasargs(entry[0], args)
789 defaults = ui.config(b"defaults", cmd)
789 defaults = ui.config(b"defaults", cmd)
790 if defaults:
790 if defaults:
791 args = (
791 args = (
792 pycompat.maplist(util.expandpath, pycompat.shlexsplit(defaults))
792 pycompat.maplist(util.expandpath, pycompat.shlexsplit(defaults))
793 + args
793 + args
794 )
794 )
795 c = list(entry[1])
795 c = list(entry[1])
796 else:
796 else:
797 cmd = None
797 cmd = None
798 c = []
798 c = []
799
799
800 # combine global options into local
800 # combine global options into local
801 for o in commands.globalopts:
801 for o in commands.globalopts:
802 c.append((o[0], o[1], options[o[1]], o[3]))
802 c.append((o[0], o[1], options[o[1]], o[3]))
803
803
804 try:
804 try:
805 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
805 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
806 except getopt.GetoptError as inst:
806 except getopt.GetoptError as inst:
807 raise error.CommandError(cmd, stringutil.forcebytestr(inst))
807 raise error.CommandError(cmd, stringutil.forcebytestr(inst))
808
808
809 # separate global options back out
809 # separate global options back out
810 for o in commands.globalopts:
810 for o in commands.globalopts:
811 n = o[1]
811 n = o[1]
812 options[n] = cmdoptions[n]
812 options[n] = cmdoptions[n]
813 del cmdoptions[n]
813 del cmdoptions[n]
814
814
815 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
815 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
816
816
817
817
818 def _parseconfig(ui, config):
818 def _parseconfig(ui, config):
819 """parse the --config options from the command line"""
819 """parse the --config options from the command line"""
820 configs = []
820 configs = []
821
821
822 for cfg in config:
822 for cfg in config:
823 try:
823 try:
824 name, value = [cfgelem.strip() for cfgelem in cfg.split(b'=', 1)]
824 name, value = [cfgelem.strip() for cfgelem in cfg.split(b'=', 1)]
825 section, name = name.split(b'.', 1)
825 section, name = name.split(b'.', 1)
826 if not section or not name:
826 if not section or not name:
827 raise IndexError
827 raise IndexError
828 ui.setconfig(section, name, value, b'--config')
828 ui.setconfig(section, name, value, b'--config')
829 configs.append((section, name, value))
829 configs.append((section, name, value))
830 except (IndexError, ValueError):
830 except (IndexError, ValueError):
831 raise error.Abort(
831 raise error.Abort(
832 _(
832 _(
833 b'malformed --config option: %r '
833 b'malformed --config option: %r '
834 b'(use --config section.name=value)'
834 b'(use --config section.name=value)'
835 )
835 )
836 % pycompat.bytestr(cfg)
836 % pycompat.bytestr(cfg)
837 )
837 )
838
838
839 return configs
839 return configs
840
840
841
841
842 def _earlyparseopts(ui, args):
842 def _earlyparseopts(ui, args):
843 options = {}
843 options = {}
844 fancyopts.fancyopts(
844 fancyopts.fancyopts(
845 args,
845 args,
846 commands.globalopts,
846 commands.globalopts,
847 options,
847 options,
848 gnu=not ui.plain(b'strictflags'),
848 gnu=not ui.plain(b'strictflags'),
849 early=True,
849 early=True,
850 optaliases={b'repository': [b'repo']},
850 optaliases={b'repository': [b'repo']},
851 )
851 )
852 return options
852 return options
853
853
854
854
855 def _earlysplitopts(args):
855 def _earlysplitopts(args):
856 """Split args into a list of possible early options and remainder args"""
856 """Split args into a list of possible early options and remainder args"""
857 shortoptions = b'R:'
857 shortoptions = b'R:'
858 # TODO: perhaps 'debugger' should be included
858 # TODO: perhaps 'debugger' should be included
859 longoptions = [b'cwd=', b'repository=', b'repo=', b'config=']
859 longoptions = [b'cwd=', b'repository=', b'repo=', b'config=']
860 return fancyopts.earlygetopt(
860 return fancyopts.earlygetopt(
861 args, shortoptions, longoptions, gnu=True, keepsep=True
861 args, shortoptions, longoptions, gnu=True, keepsep=True
862 )
862 )
863
863
864
864
865 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
865 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
866 # run pre-hook, and abort if it fails
866 # run pre-hook, and abort if it fails
867 hook.hook(
867 hook.hook(
868 lui,
868 lui,
869 repo,
869 repo,
870 b"pre-%s" % cmd,
870 b"pre-%s" % cmd,
871 True,
871 True,
872 args=b" ".join(fullargs),
872 args=b" ".join(fullargs),
873 pats=cmdpats,
873 pats=cmdpats,
874 opts=cmdoptions,
874 opts=cmdoptions,
875 )
875 )
876 try:
876 try:
877 ret = _runcommand(ui, options, cmd, d)
877 ret = _runcommand(ui, options, cmd, d)
878 # run post-hook, passing command result
878 # run post-hook, passing command result
879 hook.hook(
879 hook.hook(
880 lui,
880 lui,
881 repo,
881 repo,
882 b"post-%s" % cmd,
882 b"post-%s" % cmd,
883 False,
883 False,
884 args=b" ".join(fullargs),
884 args=b" ".join(fullargs),
885 result=ret,
885 result=ret,
886 pats=cmdpats,
886 pats=cmdpats,
887 opts=cmdoptions,
887 opts=cmdoptions,
888 )
888 )
889 except Exception:
889 except Exception:
890 # run failure hook and re-raise
890 # run failure hook and re-raise
891 hook.hook(
891 hook.hook(
892 lui,
892 lui,
893 repo,
893 repo,
894 b"fail-%s" % cmd,
894 b"fail-%s" % cmd,
895 False,
895 False,
896 args=b" ".join(fullargs),
896 args=b" ".join(fullargs),
897 pats=cmdpats,
897 pats=cmdpats,
898 opts=cmdoptions,
898 opts=cmdoptions,
899 )
899 )
900 raise
900 raise
901 return ret
901 return ret
902
902
903
903
904 def _readsharedsourceconfig(ui, path):
904 def _readsharedsourceconfig(ui, path):
905 """if the current repository is shared one, this tries to read
905 """if the current repository is shared one, this tries to read
906 .hg/hgrc of shared source if we are in share-safe mode
906 .hg/hgrc of shared source if we are in share-safe mode
907
907
908 Config read is loaded into the ui object passed
908 Config read is loaded into the ui object passed
909
909
910 This should be called before reading .hg/hgrc or the main repo
910 This should be called before reading .hg/hgrc or the main repo
911 as that overrides config set in shared source"""
911 as that overrides config set in shared source"""
912 try:
912 try:
913 with open(os.path.join(path, b".hg", b"requires"), "rb") as fp:
913 with open(os.path.join(path, b".hg", b"requires"), "rb") as fp:
914 requirements = set(fp.read().splitlines())
914 requirements = set(fp.read().splitlines())
915 if not (
915 if not (
916 requirementsmod.SHARESAFE_REQUIREMENT in requirements
916 requirementsmod.SHARESAFE_REQUIREMENT in requirements
917 and requirementsmod.SHARED_REQUIREMENT in requirements
917 and requirementsmod.SHARED_REQUIREMENT in requirements
918 ):
918 ):
919 return
919 return
920 hgvfs = vfs.vfs(os.path.join(path, b".hg"))
920 hgvfs = vfs.vfs(os.path.join(path, b".hg"))
921 sharedvfs = localrepo._getsharedvfs(hgvfs, requirements)
921 sharedvfs = localrepo._getsharedvfs(hgvfs, requirements)
922 ui.readconfig(sharedvfs.join(b"hgrc"), path)
922 ui.readconfig(sharedvfs.join(b"hgrc"), path)
923 except IOError:
923 except IOError:
924 pass
924 pass
925
925
926
926
927 def _getlocal(ui, rpath, wd=None):
927 def _getlocal(ui, rpath, wd=None):
928 """Return (path, local ui object) for the given target path.
928 """Return (path, local ui object) for the given target path.
929
929
930 Takes paths in [cwd]/.hg/hgrc into account."
930 Takes paths in [cwd]/.hg/hgrc into account."
931 """
931 """
932 if wd is None:
932 if wd is None:
933 try:
933 try:
934 wd = encoding.getcwd()
934 wd = encoding.getcwd()
935 except OSError as e:
935 except OSError as e:
936 raise error.Abort(
936 raise error.Abort(
937 _(b"error getting current working directory: %s")
937 _(b"error getting current working directory: %s")
938 % encoding.strtolocal(e.strerror)
938 % encoding.strtolocal(e.strerror)
939 )
939 )
940
940
941 path = cmdutil.findrepo(wd) or b""
941 path = cmdutil.findrepo(wd) or b""
942 if not path:
942 if not path:
943 lui = ui
943 lui = ui
944 else:
944 else:
945 lui = ui.copy()
945 lui = ui.copy()
946 if rcutil.use_repo_hgrc():
946 if rcutil.use_repo_hgrc():
947 _readsharedsourceconfig(lui, path)
947 _readsharedsourceconfig(lui, path)
948 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path)
948 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path)
949 lui.readconfig(os.path.join(path, b".hg", b"hgrc-not-shared"), path)
949 lui.readconfig(os.path.join(path, b".hg", b"hgrc-not-shared"), path)
950
950
951 if rpath:
951 if rpath:
952 path = lui.expandpath(rpath)
952 path = lui.expandpath(rpath)
953 lui = ui.copy()
953 lui = ui.copy()
954 if rcutil.use_repo_hgrc():
954 if rcutil.use_repo_hgrc():
955 _readsharedsourceconfig(lui, path)
955 _readsharedsourceconfig(lui, path)
956 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path)
956 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path)
957 lui.readconfig(os.path.join(path, b".hg", b"hgrc-not-shared"), path)
957 lui.readconfig(os.path.join(path, b".hg", b"hgrc-not-shared"), path)
958
958
959 return path, lui
959 return path, lui
960
960
961
961
962 def _checkshellalias(lui, ui, args):
962 def _checkshellalias(lui, ui, args):
963 """Return the function to run the shell alias, if it is required"""
963 """Return the function to run the shell alias, if it is required"""
964 options = {}
964 options = {}
965
965
966 try:
966 try:
967 args = fancyopts.fancyopts(args, commands.globalopts, options)
967 args = fancyopts.fancyopts(args, commands.globalopts, options)
968 except getopt.GetoptError:
968 except getopt.GetoptError:
969 return
969 return
970
970
971 if not args:
971 if not args:
972 return
972 return
973
973
974 cmdtable = commands.table
974 cmdtable = commands.table
975
975
976 cmd = args[0]
976 cmd = args[0]
977 try:
977 try:
978 strict = ui.configbool(b"ui", b"strict")
978 strict = ui.configbool(b"ui", b"strict")
979 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
979 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
980 except (error.AmbiguousCommand, error.UnknownCommand):
980 except (error.AmbiguousCommand, error.UnknownCommand):
981 return
981 return
982
982
983 cmd = aliases[0]
983 cmd = aliases[0]
984 fn = entry[0]
984 fn = entry[0]
985
985
986 if cmd and util.safehasattr(fn, b'shell'):
986 if cmd and util.safehasattr(fn, b'shell'):
987 # shell alias shouldn't receive early options which are consumed by hg
987 # shell alias shouldn't receive early options which are consumed by hg
988 _earlyopts, args = _earlysplitopts(args)
988 _earlyopts, args = _earlysplitopts(args)
989 d = lambda: fn(ui, *args[1:])
989 d = lambda: fn(ui, *args[1:])
990 return lambda: runcommand(
990 return lambda: runcommand(
991 lui, None, cmd, args[:1], ui, options, d, [], {}
991 lui, None, cmd, args[:1], ui, options, d, [], {}
992 )
992 )
993
993
994
994
995 def _dispatch(req):
995 def _dispatch(req):
996 args = req.args
996 args = req.args
997 ui = req.ui
997 ui = req.ui
998
998
999 # check for cwd
999 # check for cwd
1000 cwd = req.earlyoptions[b'cwd']
1000 cwd = req.earlyoptions[b'cwd']
1001 if cwd:
1001 if cwd:
1002 os.chdir(cwd)
1002 os.chdir(cwd)
1003
1003
1004 rpath = req.earlyoptions[b'repository']
1004 rpath = req.earlyoptions[b'repository']
1005 path, lui = _getlocal(ui, rpath)
1005 path, lui = _getlocal(ui, rpath)
1006
1006
1007 uis = {ui, lui}
1007 uis = {ui, lui}
1008
1008
1009 if req.repo:
1009 if req.repo:
1010 uis.add(req.repo.ui)
1010 uis.add(req.repo.ui)
1011
1011
1012 if (
1012 if (
1013 req.earlyoptions[b'verbose']
1013 req.earlyoptions[b'verbose']
1014 or req.earlyoptions[b'debug']
1014 or req.earlyoptions[b'debug']
1015 or req.earlyoptions[b'quiet']
1015 or req.earlyoptions[b'quiet']
1016 ):
1016 ):
1017 for opt in (b'verbose', b'debug', b'quiet'):
1017 for opt in (b'verbose', b'debug', b'quiet'):
1018 val = pycompat.bytestr(bool(req.earlyoptions[opt]))
1018 val = pycompat.bytestr(bool(req.earlyoptions[opt]))
1019 for ui_ in uis:
1019 for ui_ in uis:
1020 ui_.setconfig(b'ui', opt, val, b'--' + opt)
1020 ui_.setconfig(b'ui', opt, val, b'--' + opt)
1021
1021
1022 if req.earlyoptions[b'profile']:
1022 if req.earlyoptions[b'profile']:
1023 for ui_ in uis:
1023 for ui_ in uis:
1024 ui_.setconfig(b'profiling', b'enabled', b'true', b'--profile')
1024 ui_.setconfig(b'profiling', b'enabled', b'true', b'--profile')
1025
1025
1026 profile = lui.configbool(b'profiling', b'enabled')
1026 profile = lui.configbool(b'profiling', b'enabled')
1027 with profiling.profile(lui, enabled=profile) as profiler:
1027 with profiling.profile(lui, enabled=profile) as profiler:
1028 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
1028 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
1029 # reposetup
1029 # reposetup
1030 extensions.loadall(lui)
1030 extensions.loadall(lui)
1031 # Propagate any changes to lui.__class__ by extensions
1031 # Propagate any changes to lui.__class__ by extensions
1032 ui.__class__ = lui.__class__
1032 ui.__class__ = lui.__class__
1033
1033
1034 # (uisetup and extsetup are handled in extensions.loadall)
1034 # (uisetup and extsetup are handled in extensions.loadall)
1035
1035
1036 # (reposetup is handled in hg.repository)
1036 # (reposetup is handled in hg.repository)
1037
1037
1038 addaliases(lui, commands.table)
1038 addaliases(lui, commands.table)
1039
1039
1040 # All aliases and commands are completely defined, now.
1040 # All aliases and commands are completely defined, now.
1041 # Check abbreviation/ambiguity of shell alias.
1041 # Check abbreviation/ambiguity of shell alias.
1042 shellaliasfn = _checkshellalias(lui, ui, args)
1042 shellaliasfn = _checkshellalias(lui, ui, args)
1043 if shellaliasfn:
1043 if shellaliasfn:
1044 # no additional configs will be set, set up the ui instances
1044 # no additional configs will be set, set up the ui instances
1045 for ui_ in uis:
1045 for ui_ in uis:
1046 extensions.populateui(ui_)
1046 extensions.populateui(ui_)
1047 return shellaliasfn()
1047 return shellaliasfn()
1048
1048
1049 # check for fallback encoding
1049 # check for fallback encoding
1050 fallback = lui.config(b'ui', b'fallbackencoding')
1050 fallback = lui.config(b'ui', b'fallbackencoding')
1051 if fallback:
1051 if fallback:
1052 encoding.fallbackencoding = fallback
1052 encoding.fallbackencoding = fallback
1053
1053
1054 fullargs = args
1054 fullargs = args
1055 cmd, func, args, options, cmdoptions = _parse(lui, args)
1055 cmd, func, args, options, cmdoptions = _parse(lui, args)
1056
1056
1057 # store the canonical command name in request object for later access
1057 # store the canonical command name in request object for later access
1058 req.canonical_command = cmd
1058 req.canonical_command = cmd
1059
1059
1060 if options[b"config"] != req.earlyoptions[b"config"]:
1060 if options[b"config"] != req.earlyoptions[b"config"]:
1061 raise error.Abort(_(b"option --config may not be abbreviated"))
1061 raise error.Abort(_(b"option --config may not be abbreviated"))
1062 if options[b"cwd"] != req.earlyoptions[b"cwd"]:
1062 if options[b"cwd"] != req.earlyoptions[b"cwd"]:
1063 raise error.Abort(_(b"option --cwd may not be abbreviated"))
1063 raise error.Abort(_(b"option --cwd may not be abbreviated"))
1064 if options[b"repository"] != req.earlyoptions[b"repository"]:
1064 if options[b"repository"] != req.earlyoptions[b"repository"]:
1065 raise error.Abort(
1065 raise error.Abort(
1066 _(
1066 _(
1067 b"option -R has to be separated from other options (e.g. not "
1067 b"option -R has to be separated from other options (e.g. not "
1068 b"-qR) and --repository may only be abbreviated as --repo"
1068 b"-qR) and --repository may only be abbreviated as --repo"
1069 )
1069 )
1070 )
1070 )
1071 if options[b"debugger"] != req.earlyoptions[b"debugger"]:
1071 if options[b"debugger"] != req.earlyoptions[b"debugger"]:
1072 raise error.Abort(_(b"option --debugger may not be abbreviated"))
1072 raise error.Abort(_(b"option --debugger may not be abbreviated"))
1073 # don't validate --profile/--traceback, which can be enabled from now
1073 # don't validate --profile/--traceback, which can be enabled from now
1074
1074
1075 if options[b"encoding"]:
1075 if options[b"encoding"]:
1076 encoding.encoding = options[b"encoding"]
1076 encoding.encoding = options[b"encoding"]
1077 if options[b"encodingmode"]:
1077 if options[b"encodingmode"]:
1078 encoding.encodingmode = options[b"encodingmode"]
1078 encoding.encodingmode = options[b"encodingmode"]
1079 if options[b"time"]:
1079 if options[b"time"]:
1080
1080
1081 def get_times():
1081 def get_times():
1082 t = os.times()
1082 t = os.times()
1083 if t[4] == 0.0:
1083 if t[4] == 0.0:
1084 # Windows leaves this as zero, so use time.perf_counter()
1084 # Windows leaves this as zero, so use time.perf_counter()
1085 t = (t[0], t[1], t[2], t[3], util.timer())
1085 t = (t[0], t[1], t[2], t[3], util.timer())
1086 return t
1086 return t
1087
1087
1088 s = get_times()
1088 s = get_times()
1089
1089
1090 def print_time():
1090 def print_time():
1091 t = get_times()
1091 t = get_times()
1092 ui.warn(
1092 ui.warn(
1093 _(b"time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n")
1093 _(b"time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n")
1094 % (
1094 % (
1095 t[4] - s[4],
1095 t[4] - s[4],
1096 t[0] - s[0],
1096 t[0] - s[0],
1097 t[2] - s[2],
1097 t[2] - s[2],
1098 t[1] - s[1],
1098 t[1] - s[1],
1099 t[3] - s[3],
1099 t[3] - s[3],
1100 )
1100 )
1101 )
1101 )
1102
1102
1103 ui.atexit(print_time)
1103 ui.atexit(print_time)
1104 if options[b"profile"]:
1104 if options[b"profile"]:
1105 profiler.start()
1105 profiler.start()
1106
1106
1107 # if abbreviated version of this were used, take them in account, now
1107 # if abbreviated version of this were used, take them in account, now
1108 if options[b'verbose'] or options[b'debug'] or options[b'quiet']:
1108 if options[b'verbose'] or options[b'debug'] or options[b'quiet']:
1109 for opt in (b'verbose', b'debug', b'quiet'):
1109 for opt in (b'verbose', b'debug', b'quiet'):
1110 if options[opt] == req.earlyoptions[opt]:
1110 if options[opt] == req.earlyoptions[opt]:
1111 continue
1111 continue
1112 val = pycompat.bytestr(bool(options[opt]))
1112 val = pycompat.bytestr(bool(options[opt]))
1113 for ui_ in uis:
1113 for ui_ in uis:
1114 ui_.setconfig(b'ui', opt, val, b'--' + opt)
1114 ui_.setconfig(b'ui', opt, val, b'--' + opt)
1115
1115
1116 if options[b'traceback']:
1116 if options[b'traceback']:
1117 for ui_ in uis:
1117 for ui_ in uis:
1118 ui_.setconfig(b'ui', b'traceback', b'on', b'--traceback')
1118 ui_.setconfig(b'ui', b'traceback', b'on', b'--traceback')
1119
1119
1120 if options[b'noninteractive']:
1120 if options[b'noninteractive']:
1121 for ui_ in uis:
1121 for ui_ in uis:
1122 ui_.setconfig(b'ui', b'interactive', b'off', b'-y')
1122 ui_.setconfig(b'ui', b'interactive', b'off', b'-y')
1123
1123
1124 if cmdoptions.get(b'insecure', False):
1124 if cmdoptions.get(b'insecure', False):
1125 for ui_ in uis:
1125 for ui_ in uis:
1126 ui_.insecureconnections = True
1126 ui_.insecureconnections = True
1127
1127
1128 # setup color handling before pager, because setting up pager
1128 # setup color handling before pager, because setting up pager
1129 # might cause incorrect console information
1129 # might cause incorrect console information
1130 coloropt = options[b'color']
1130 coloropt = options[b'color']
1131 for ui_ in uis:
1131 for ui_ in uis:
1132 if coloropt:
1132 if coloropt:
1133 ui_.setconfig(b'ui', b'color', coloropt, b'--color')
1133 ui_.setconfig(b'ui', b'color', coloropt, b'--color')
1134 color.setup(ui_)
1134 color.setup(ui_)
1135
1135
1136 if stringutil.parsebool(options[b'pager']):
1136 if stringutil.parsebool(options[b'pager']):
1137 # ui.pager() expects 'internal-always-' prefix in this case
1137 # ui.pager() expects 'internal-always-' prefix in this case
1138 ui.pager(b'internal-always-' + cmd)
1138 ui.pager(b'internal-always-' + cmd)
1139 elif options[b'pager'] != b'auto':
1139 elif options[b'pager'] != b'auto':
1140 for ui_ in uis:
1140 for ui_ in uis:
1141 ui_.disablepager()
1141 ui_.disablepager()
1142
1142
1143 # configs are fully loaded, set up the ui instances
1143 # configs are fully loaded, set up the ui instances
1144 for ui_ in uis:
1144 for ui_ in uis:
1145 extensions.populateui(ui_)
1145 extensions.populateui(ui_)
1146
1146
1147 if options[b'version']:
1147 if options[b'version']:
1148 return commands.version_(ui)
1148 return commands.version_(ui)
1149 if options[b'help']:
1149 if options[b'help']:
1150 return commands.help_(ui, cmd, command=cmd is not None)
1150 return commands.help_(ui, cmd, command=cmd is not None)
1151 elif not cmd:
1151 elif not cmd:
1152 return commands.help_(ui, b'shortlist')
1152 return commands.help_(ui, b'shortlist')
1153
1153
1154 repo = None
1154 repo = None
1155 cmdpats = args[:]
1155 cmdpats = args[:]
1156 assert func is not None # help out pytype
1156 assert func is not None # help out pytype
1157 if not func.norepo:
1157 if not func.norepo:
1158 # use the repo from the request only if we don't have -R
1158 # use the repo from the request only if we don't have -R
1159 if not rpath and not cwd:
1159 if not rpath and not cwd:
1160 repo = req.repo
1160 repo = req.repo
1161
1161
1162 if repo:
1162 if repo:
1163 # set the descriptors of the repo ui to those of ui
1163 # set the descriptors of the repo ui to those of ui
1164 repo.ui.fin = ui.fin
1164 repo.ui.fin = ui.fin
1165 repo.ui.fout = ui.fout
1165 repo.ui.fout = ui.fout
1166 repo.ui.ferr = ui.ferr
1166 repo.ui.ferr = ui.ferr
1167 repo.ui.fmsg = ui.fmsg
1167 repo.ui.fmsg = ui.fmsg
1168 else:
1168 else:
1169 try:
1169 try:
1170 repo = hg.repository(
1170 repo = hg.repository(
1171 ui,
1171 ui,
1172 path=path,
1172 path=path,
1173 presetupfuncs=req.prereposetups,
1173 presetupfuncs=req.prereposetups,
1174 intents=func.intents,
1174 intents=func.intents,
1175 )
1175 )
1176 if not repo.local():
1176 if not repo.local():
1177 raise error.InputError(
1177 raise error.InputError(
1178 _(b"repository '%s' is not local") % path
1178 _(b"repository '%s' is not local") % path
1179 )
1179 )
1180 repo.ui.setconfig(
1180 repo.ui.setconfig(
1181 b"bundle", b"mainreporoot", repo.root, b'repo'
1181 b"bundle", b"mainreporoot", repo.root, b'repo'
1182 )
1182 )
1183 except error.RequirementError:
1183 except error.RequirementError:
1184 raise
1184 raise
1185 except error.RepoError:
1185 except error.RepoError:
1186 if rpath: # invalid -R path
1186 if rpath: # invalid -R path
1187 raise
1187 raise
1188 if not func.optionalrepo:
1188 if not func.optionalrepo:
1189 if func.inferrepo and args and not path:
1189 if func.inferrepo and args and not path:
1190 # try to infer -R from command args
1190 # try to infer -R from command args
1191 repos = pycompat.maplist(cmdutil.findrepo, args)
1191 repos = pycompat.maplist(cmdutil.findrepo, args)
1192 guess = repos[0]
1192 guess = repos[0]
1193 if guess and repos.count(guess) == len(repos):
1193 if guess and repos.count(guess) == len(repos):
1194 req.args = [b'--repository', guess] + fullargs
1194 req.args = [b'--repository', guess] + fullargs
1195 req.earlyoptions[b'repository'] = guess
1195 req.earlyoptions[b'repository'] = guess
1196 return _dispatch(req)
1196 return _dispatch(req)
1197 if not path:
1197 if not path:
1198 raise error.InputError(
1198 raise error.InputError(
1199 _(
1199 _(
1200 b"no repository found in"
1200 b"no repository found in"
1201 b" '%s' (.hg not found)"
1201 b" '%s' (.hg not found)"
1202 )
1202 )
1203 % encoding.getcwd()
1203 % encoding.getcwd()
1204 )
1204 )
1205 raise
1205 raise
1206 if repo:
1206 if repo:
1207 ui = repo.ui
1207 ui = repo.ui
1208 if options[b'hidden']:
1208 if options[b'hidden']:
1209 repo = repo.unfiltered()
1209 repo = repo.unfiltered()
1210 args.insert(0, repo)
1210 args.insert(0, repo)
1211 elif rpath:
1211 elif rpath:
1212 ui.warn(_(b"warning: --repository ignored\n"))
1212 ui.warn(_(b"warning: --repository ignored\n"))
1213
1213
1214 msg = _formatargs(fullargs)
1214 msg = _formatargs(fullargs)
1215 ui.log(b"command", b'%s\n', msg)
1215 ui.log(b"command", b'%s\n', msg)
1216 strcmdopt = pycompat.strkwargs(cmdoptions)
1216 strcmdopt = pycompat.strkwargs(cmdoptions)
1217 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
1217 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
1218 try:
1218 try:
1219 return runcommand(
1219 return runcommand(
1220 lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions
1220 lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions
1221 )
1221 )
1222 finally:
1222 finally:
1223 if repo and repo != req.repo:
1223 if repo and repo != req.repo:
1224 repo.close()
1224 repo.close()
1225
1225
1226
1226
1227 def _runcommand(ui, options, cmd, cmdfunc):
1227 def _runcommand(ui, options, cmd, cmdfunc):
1228 """Run a command function, possibly with profiling enabled."""
1228 """Run a command function, possibly with profiling enabled."""
1229 try:
1229 try:
1230 with tracing.log("Running %s command" % cmd):
1230 with tracing.log("Running %s command" % cmd):
1231 return cmdfunc()
1231 return cmdfunc()
1232 except error.SignatureError:
1232 except error.SignatureError:
1233 raise error.CommandError(cmd, _(b'invalid arguments'))
1233 raise error.CommandError(cmd, _(b'invalid arguments'))
1234
1234
1235
1235
1236 def _exceptionwarning(ui):
1236 def _exceptionwarning(ui):
1237 """Produce a warning message for the current active exception"""
1237 """Produce a warning message for the current active exception"""
1238
1238
1239 # For compatibility checking, we discard the portion of the hg
1239 # For compatibility checking, we discard the portion of the hg
1240 # version after the + on the assumption that if a "normal
1240 # version after the + on the assumption that if a "normal
1241 # user" is running a build with a + in it the packager
1241 # user" is running a build with a + in it the packager
1242 # probably built from fairly close to a tag and anyone with a
1242 # probably built from fairly close to a tag and anyone with a
1243 # 'make local' copy of hg (where the version number can be out
1243 # 'make local' copy of hg (where the version number can be out
1244 # of date) will be clueful enough to notice the implausible
1244 # of date) will be clueful enough to notice the implausible
1245 # version number and try updating.
1245 # version number and try updating.
1246 ct = util.versiontuple(n=2)
1246 ct = util.versiontuple(n=2)
1247 worst = None, ct, b''
1247 worst = None, ct, b''
1248 if ui.config(b'ui', b'supportcontact') is None:
1248 if ui.config(b'ui', b'supportcontact') is None:
1249 for name, mod in extensions.extensions():
1249 for name, mod in extensions.extensions():
1250 # 'testedwith' should be bytes, but not all extensions are ported
1250 # 'testedwith' should be bytes, but not all extensions are ported
1251 # to py3 and we don't want UnicodeException because of that.
1251 # to py3 and we don't want UnicodeException because of that.
1252 testedwith = stringutil.forcebytestr(
1252 testedwith = stringutil.forcebytestr(
1253 getattr(mod, 'testedwith', b'')
1253 getattr(mod, 'testedwith', b'')
1254 )
1254 )
1255 report = getattr(mod, 'buglink', _(b'the extension author.'))
1255 report = getattr(mod, 'buglink', _(b'the extension author.'))
1256 if not testedwith.strip():
1256 if not testedwith.strip():
1257 # We found an untested extension. It's likely the culprit.
1257 # We found an untested extension. It's likely the culprit.
1258 worst = name, b'unknown', report
1258 worst = name, b'unknown', report
1259 break
1259 break
1260
1260
1261 # Never blame on extensions bundled with Mercurial.
1261 # Never blame on extensions bundled with Mercurial.
1262 if extensions.ismoduleinternal(mod):
1262 if extensions.ismoduleinternal(mod):
1263 continue
1263 continue
1264
1264
1265 tested = [util.versiontuple(t, 2) for t in testedwith.split()]
1265 tested = [util.versiontuple(t, 2) for t in testedwith.split()]
1266 if ct in tested:
1266 if ct in tested:
1267 continue
1267 continue
1268
1268
1269 lower = [t for t in tested if t < ct]
1269 lower = [t for t in tested if t < ct]
1270 nearest = max(lower or tested)
1270 nearest = max(lower or tested)
1271 if worst[0] is None or nearest < worst[1]:
1271 if worst[0] is None or nearest < worst[1]:
1272 worst = name, nearest, report
1272 worst = name, nearest, report
1273 if worst[0] is not None:
1273 if worst[0] is not None:
1274 name, testedwith, report = worst
1274 name, testedwith, report = worst
1275 if not isinstance(testedwith, (bytes, str)):
1275 if not isinstance(testedwith, (bytes, str)):
1276 testedwith = b'.'.join(
1276 testedwith = b'.'.join(
1277 [stringutil.forcebytestr(c) for c in testedwith]
1277 [stringutil.forcebytestr(c) for c in testedwith]
1278 )
1278 )
1279 warning = _(
1279 warning = _(
1280 b'** Unknown exception encountered with '
1280 b'** Unknown exception encountered with '
1281 b'possibly-broken third-party extension %s\n'
1281 b'possibly-broken third-party extension %s\n'
1282 b'** which supports versions %s of Mercurial.\n'
1282 b'** which supports versions %s of Mercurial.\n'
1283 b'** Please disable %s and try your action again.\n'
1283 b'** Please disable %s and try your action again.\n'
1284 b'** If that fixes the bug please report it to %s\n'
1284 b'** If that fixes the bug please report it to %s\n'
1285 ) % (name, testedwith, name, stringutil.forcebytestr(report))
1285 ) % (name, testedwith, name, stringutil.forcebytestr(report))
1286 else:
1286 else:
1287 bugtracker = ui.config(b'ui', b'supportcontact')
1287 bugtracker = ui.config(b'ui', b'supportcontact')
1288 if bugtracker is None:
1288 if bugtracker is None:
1289 bugtracker = _(b"https://mercurial-scm.org/wiki/BugTracker")
1289 bugtracker = _(b"https://mercurial-scm.org/wiki/BugTracker")
1290 warning = (
1290 warning = (
1291 _(
1291 _(
1292 b"** unknown exception encountered, "
1292 b"** unknown exception encountered, "
1293 b"please report by visiting\n** "
1293 b"please report by visiting\n** "
1294 )
1294 )
1295 + bugtracker
1295 + bugtracker
1296 + b'\n'
1296 + b'\n'
1297 )
1297 )
1298 sysversion = pycompat.sysbytes(sys.version).replace(b'\n', b'')
1298 sysversion = pycompat.sysbytes(sys.version).replace(b'\n', b'')
1299 warning += (
1299 warning += (
1300 (_(b"** Python %s\n") % sysversion)
1300 (_(b"** Python %s\n") % sysversion)
1301 + (_(b"** Mercurial Distributed SCM (version %s)\n") % util.version())
1301 + (_(b"** Mercurial Distributed SCM (version %s)\n") % util.version())
1302 + (
1302 + (
1303 _(b"** Extensions loaded: %s\n")
1303 _(b"** Extensions loaded: %s\n")
1304 % b", ".join([x[0] for x in extensions.extensions()])
1304 % b", ".join([x[0] for x in extensions.extensions()])
1305 )
1305 )
1306 )
1306 )
1307 return warning
1307 return warning
1308
1308
1309
1309
1310 def handlecommandexception(ui):
1310 def handlecommandexception(ui):
1311 """Produce a warning message for broken commands
1311 """Produce a warning message for broken commands
1312
1312
1313 Called when handling an exception; the exception is reraised if
1313 Called when handling an exception; the exception is reraised if
1314 this function returns False, ignored otherwise.
1314 this function returns False, ignored otherwise.
1315 """
1315 """
1316 warning = _exceptionwarning(ui)
1316 warning = _exceptionwarning(ui)
1317 ui.log(
1317 ui.log(
1318 b"commandexception",
1318 b"commandexception",
1319 b"%s\n%s\n",
1319 b"%s\n%s\n",
1320 warning,
1320 warning,
1321 pycompat.sysbytes(traceback.format_exc()),
1321 pycompat.sysbytes(traceback.format_exc()),
1322 )
1322 )
1323 ui.warn(warning)
1323 ui.warn(warning)
1324 return False # re-raise the exception
1324 return False # re-raise the exception
@@ -1,722 +1,722 b''
1 $ HGFOO=BAR; export HGFOO
1 $ HGFOO=BAR; export HGFOO
2 $ cat >> $HGRCPATH <<EOF
2 $ cat >> $HGRCPATH <<EOF
3 > [alias]
3 > [alias]
4 > # should clobber ci but not commit (issue2993)
4 > # should clobber ci but not commit (issue2993)
5 > ci = version
5 > ci = version
6 > myinit = init
6 > myinit = init
7 > myinit:doc = This is my documented alias for init.
7 > myinit:doc = This is my documented alias for init.
8 > myinit:help = [OPTIONS] [BLA] [BLE]
8 > myinit:help = [OPTIONS] [BLA] [BLE]
9 > mycommit = commit
9 > mycommit = commit
10 > mycommit:doc = This is my alias with only doc.
10 > mycommit:doc = This is my alias with only doc.
11 > optionalrepo = showconfig alias.myinit
11 > optionalrepo = showconfig alias.myinit
12 > cleanstatus = status -c
12 > cleanstatus = status -c
13 > cleanstatus:help = [ONLYHELPHERE]
13 > cleanstatus:help = [ONLYHELPHERE]
14 > unknown = bargle
14 > unknown = bargle
15 > ambiguous = s
15 > ambiguous = s
16 > recursive = recursive
16 > recursive = recursive
17 > disabled = email
17 > disabled = email
18 > nodefinition =
18 > nodefinition =
19 > noclosingquotation = '
19 > noclosingquotation = '
20 > no--cwd = status --cwd elsewhere
20 > no--cwd = status --cwd elsewhere
21 > no-R = status -R elsewhere
21 > no-R = status -R elsewhere
22 > no--repo = status --repo elsewhere
22 > no--repo = status --repo elsewhere
23 > no--repository = status --repository elsewhere
23 > no--repository = status --repository elsewhere
24 > no--config = status --config a.config=1
24 > no--config = status --config a.config=1
25 > mylog = log
25 > mylog = log
26 > lognull = log -r null
26 > lognull = log -r null
27 > lognull:doc = Logs the null rev
27 > lognull:doc = Logs the null rev
28 > lognull:help = foo bar baz
28 > lognull:help = foo bar baz
29 > shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
29 > shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
30 > positional = log --template '{\$2} {\$1} | {date|isodate}\n'
30 > positional = log --template '{\$2} {\$1} | {date|isodate}\n'
31 > dln = lognull --debug
31 > dln = lognull --debug
32 > recursivedoc = dln
32 > recursivedoc = dln
33 > recursivedoc:doc = Logs the null rev in debug mode
33 > recursivedoc:doc = Logs the null rev in debug mode
34 > nousage = rollback
34 > nousage = rollback
35 > put = export -r 0 -o "\$FOO/%R.diff"
35 > put = export -r 0 -o "\$FOO/%R.diff"
36 > blank = !printf '\n'
36 > blank = !printf '\n'
37 > self = !printf '\$0\n'
37 > self = !printf '\$0\n'
38 > echoall = !printf '\$@\n'
38 > echoall = !printf '\$@\n'
39 > echo1 = !printf '\$1\n'
39 > echo1 = !printf '\$1\n'
40 > echo2 = !printf '\$2\n'
40 > echo2 = !printf '\$2\n'
41 > echo13 = !printf '\$1 \$3\n'
41 > echo13 = !printf '\$1 \$3\n'
42 > echotokens = !printf "%s\n" "\$@"
42 > echotokens = !printf "%s\n" "\$@"
43 > count = !hg log -r "\$@" --template=. | wc -c | sed -e 's/ //g'
43 > count = !hg log -r "\$@" --template=. | wc -c | sed -e 's/ //g'
44 > mcount = !hg log \$@ --template=. | wc -c | sed -e 's/ //g'
44 > mcount = !hg log \$@ --template=. | wc -c | sed -e 's/ //g'
45 > rt = root
45 > rt = root
46 > tglog = log -G --template "{rev}:{node|short}: '{desc}' {branches}\n"
46 > tglog = log -G --template "{rev}:{node|short}: '{desc}' {branches}\n"
47 > idalias = id
47 > idalias = id
48 > idaliaslong = id
48 > idaliaslong = id
49 > idaliasshell = !echo test
49 > idaliasshell = !echo test
50 > parentsshell1 = !echo one
50 > parentsshell1 = !echo one
51 > parentsshell2 = !echo two
51 > parentsshell2 = !echo two
52 > escaped1 = !printf 'test\$\$test\n'
52 > escaped1 = !printf 'test\$\$test\n'
53 > escaped2 = !sh -c 'echo "HGFOO is \$\$HGFOO"'
53 > escaped2 = !sh -c 'echo "HGFOO is \$\$HGFOO"'
54 > escaped3 = !sh -c 'echo "\$1 is \$\$\$1"'
54 > escaped3 = !sh -c 'echo "\$1 is \$\$\$1"'
55 > escaped4 = !printf '\$\$0 \$\$@\n'
55 > escaped4 = !printf '\$\$0 \$\$@\n'
56 > exit1 = !sh -c 'exit 1'
56 > exit1 = !sh -c 'exit 1'
57 >
57 >
58 > [defaults]
58 > [defaults]
59 > mylog = -q
59 > mylog = -q
60 > lognull = -q
60 > lognull = -q
61 > log = -v
61 > log = -v
62 > EOF
62 > EOF
63
63
64 basic
64 basic
65
65
66 $ hg myinit alias
66 $ hg myinit alias
67
67
68 help
68 help
69
69
70 $ hg help -c | grep myinit
70 $ hg help -c | grep myinit
71 myinit This is my documented alias for init.
71 myinit This is my documented alias for init.
72 $ hg help -c | grep mycommit
72 $ hg help -c | grep mycommit
73 mycommit This is my alias with only doc.
73 mycommit This is my alias with only doc.
74 $ hg help -c | grep cleanstatus
74 $ hg help -c | grep cleanstatus
75 [1]
75 [1]
76 $ hg help -c | grep lognull
76 $ hg help -c | grep lognull
77 lognull Logs the null rev
77 lognull Logs the null rev
78 $ hg help -c | grep dln
78 $ hg help -c | grep dln
79 [1]
79 [1]
80 $ hg help -c | grep recursivedoc
80 $ hg help -c | grep recursivedoc
81 recursivedoc Logs the null rev in debug mode
81 recursivedoc Logs the null rev in debug mode
82 $ hg help myinit
82 $ hg help myinit
83 hg myinit [OPTIONS] [BLA] [BLE]
83 hg myinit [OPTIONS] [BLA] [BLE]
84
84
85 alias for: hg init
85 alias for: hg init
86
86
87 This is my documented alias for init.
87 This is my documented alias for init.
88
88
89 defined by: * (glob)
89 defined by: * (glob)
90 */* (glob) (?)
90 */* (glob) (?)
91 */* (glob) (?)
91 */* (glob) (?)
92 */* (glob) (?)
92 */* (glob) (?)
93
93
94 options:
94 options:
95
95
96 -e --ssh CMD specify ssh command to use
96 -e --ssh CMD specify ssh command to use
97 --remotecmd CMD specify hg command to run on the remote side
97 --remotecmd CMD specify hg command to run on the remote side
98 --insecure do not verify server certificate (ignoring web.cacerts
98 --insecure do not verify server certificate (ignoring web.cacerts
99 config)
99 config)
100
100
101 (some details hidden, use --verbose to show complete help)
101 (some details hidden, use --verbose to show complete help)
102
102
103 $ hg help mycommit
103 $ hg help mycommit
104 hg mycommit [OPTION]... [FILE]...
104 hg mycommit [OPTION]... [FILE]...
105
105
106 alias for: hg commit
106 alias for: hg commit
107
107
108 This is my alias with only doc.
108 This is my alias with only doc.
109
109
110 defined by: * (glob)
110 defined by: * (glob)
111 */* (glob) (?)
111 */* (glob) (?)
112 */* (glob) (?)
112 */* (glob) (?)
113 */* (glob) (?)
113 */* (glob) (?)
114
114
115 options ([+] can be repeated):
115 options ([+] can be repeated):
116
116
117 -A --addremove mark new/missing files as added/removed before
117 -A --addremove mark new/missing files as added/removed before
118 committing
118 committing
119 --close-branch mark a branch head as closed
119 --close-branch mark a branch head as closed
120 --amend amend the parent of the working directory
120 --amend amend the parent of the working directory
121 -s --secret use the secret phase for committing
121 -s --secret use the secret phase for committing
122 -e --edit invoke editor on commit messages
122 -e --edit invoke editor on commit messages
123 -i --interactive use interactive mode
123 -i --interactive use interactive mode
124 -I --include PATTERN [+] include names matching the given patterns
124 -I --include PATTERN [+] include names matching the given patterns
125 -X --exclude PATTERN [+] exclude names matching the given patterns
125 -X --exclude PATTERN [+] exclude names matching the given patterns
126 -m --message TEXT use text as commit message
126 -m --message TEXT use text as commit message
127 -l --logfile FILE read commit message from file
127 -l --logfile FILE read commit message from file
128 -d --date DATE record the specified date as commit date
128 -d --date DATE record the specified date as commit date
129 -u --user USER record the specified user as committer
129 -u --user USER record the specified user as committer
130 -S --subrepos recurse into subrepositories
130 -S --subrepos recurse into subrepositories
131
131
132 (some details hidden, use --verbose to show complete help)
132 (some details hidden, use --verbose to show complete help)
133
133
134 $ hg help cleanstatus
134 $ hg help cleanstatus
135 hg cleanstatus [ONLYHELPHERE]
135 hg cleanstatus [ONLYHELPHERE]
136
136
137 alias for: hg status -c
137 alias for: hg status -c
138
138
139 show changed files in the working directory
139 show changed files in the working directory
140
140
141 Show status of files in the repository. If names are given, only files
141 Show status of files in the repository. If names are given, only files
142 that match are shown. Files that are clean or ignored or the source of a
142 that match are shown. Files that are clean or ignored or the source of a
143 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
143 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
144 -C/--copies or -A/--all are given. Unless options described with "show
144 -C/--copies or -A/--all are given. Unless options described with "show
145 only ..." are given, the options -mardu are used.
145 only ..." are given, the options -mardu are used.
146
146
147 Option -q/--quiet hides untracked (unknown and ignored) files unless
147 Option -q/--quiet hides untracked (unknown and ignored) files unless
148 explicitly requested with -u/--unknown or -i/--ignored.
148 explicitly requested with -u/--unknown or -i/--ignored.
149
149
150 Note:
150 Note:
151 'hg status' may appear to disagree with diff if permissions have
151 'hg status' may appear to disagree with diff if permissions have
152 changed or a merge has occurred. The standard diff format does not
152 changed or a merge has occurred. The standard diff format does not
153 report permission changes and diff only reports changes relative to one
153 report permission changes and diff only reports changes relative to one
154 merge parent.
154 merge parent.
155
155
156 If one revision is given, it is used as the base revision. If two
156 If one revision is given, it is used as the base revision. If two
157 revisions are given, the differences between them are shown. The --change
157 revisions are given, the differences between them are shown. The --change
158 option can also be used as a shortcut to list the changed files of a
158 option can also be used as a shortcut to list the changed files of a
159 revision from its first parent.
159 revision from its first parent.
160
160
161 The codes used to show the status of files are:
161 The codes used to show the status of files are:
162
162
163 M = modified
163 M = modified
164 A = added
164 A = added
165 R = removed
165 R = removed
166 C = clean
166 C = clean
167 ! = missing (deleted by non-hg command, but still tracked)
167 ! = missing (deleted by non-hg command, but still tracked)
168 ? = not tracked
168 ? = not tracked
169 I = ignored
169 I = ignored
170 = origin of the previous file (with --copies)
170 = origin of the previous file (with --copies)
171
171
172 Returns 0 on success.
172 Returns 0 on success.
173
173
174 defined by: * (glob)
174 defined by: * (glob)
175 */* (glob) (?)
175 */* (glob) (?)
176 */* (glob) (?)
176 */* (glob) (?)
177 */* (glob) (?)
177 */* (glob) (?)
178
178
179 options ([+] can be repeated):
179 options ([+] can be repeated):
180
180
181 -A --all show status of all files
181 -A --all show status of all files
182 -m --modified show only modified files
182 -m --modified show only modified files
183 -a --added show only added files
183 -a --added show only added files
184 -r --removed show only removed files
184 -r --removed show only removed files
185 -d --deleted show only missing files
185 -d --deleted show only missing files
186 -c --clean show only files without changes
186 -c --clean show only files without changes
187 -u --unknown show only unknown (not tracked) files
187 -u --unknown show only unknown (not tracked) files
188 -i --ignored show only ignored files
188 -i --ignored show only ignored files
189 -n --no-status hide status prefix
189 -n --no-status hide status prefix
190 -C --copies show source of copied files
190 -C --copies show source of copied files
191 -0 --print0 end filenames with NUL, for use with xargs
191 -0 --print0 end filenames with NUL, for use with xargs
192 --rev REV [+] show difference from revision
192 --rev REV [+] show difference from revision
193 --change REV list the changed files of a revision
193 --change REV list the changed files of a revision
194 -I --include PATTERN [+] include names matching the given patterns
194 -I --include PATTERN [+] include names matching the given patterns
195 -X --exclude PATTERN [+] exclude names matching the given patterns
195 -X --exclude PATTERN [+] exclude names matching the given patterns
196 -S --subrepos recurse into subrepositories
196 -S --subrepos recurse into subrepositories
197 -T --template TEMPLATE display with template
197 -T --template TEMPLATE display with template
198
198
199 (some details hidden, use --verbose to show complete help)
199 (some details hidden, use --verbose to show complete help)
200
200
201 $ hg help recursivedoc | head -n 5
201 $ hg help recursivedoc | head -n 5
202 hg recursivedoc foo bar baz
202 hg recursivedoc foo bar baz
203
203
204 alias for: hg dln
204 alias for: hg dln
205
205
206 Logs the null rev in debug mode
206 Logs the null rev in debug mode
207
207
208 unknown
208 unknown
209
209
210 $ hg unknown
210 $ hg unknown
211 abort: alias 'unknown' resolves to unknown command 'bargle'
211 config error: alias 'unknown' resolves to unknown command 'bargle'
212 [255]
212 [30]
213 $ hg help unknown
213 $ hg help unknown
214 alias 'unknown' resolves to unknown command 'bargle'
214 alias 'unknown' resolves to unknown command 'bargle'
215
215
216
216
217 ambiguous
217 ambiguous
218
218
219 $ hg ambiguous
219 $ hg ambiguous
220 abort: alias 'ambiguous' resolves to ambiguous command 's'
220 config error: alias 'ambiguous' resolves to ambiguous command 's'
221 [255]
221 [30]
222 $ hg help ambiguous
222 $ hg help ambiguous
223 alias 'ambiguous' resolves to ambiguous command 's'
223 alias 'ambiguous' resolves to ambiguous command 's'
224
224
225
225
226 recursive
226 recursive
227
227
228 $ hg recursive
228 $ hg recursive
229 abort: alias 'recursive' resolves to unknown command 'recursive'
229 config error: alias 'recursive' resolves to unknown command 'recursive'
230 [255]
230 [30]
231 $ hg help recursive
231 $ hg help recursive
232 alias 'recursive' resolves to unknown command 'recursive'
232 alias 'recursive' resolves to unknown command 'recursive'
233
233
234
234
235 disabled
235 disabled
236
236
237 $ hg disabled
237 $ hg disabled
238 abort: alias 'disabled' resolves to unknown command 'email'
238 config error: alias 'disabled' resolves to unknown command 'email'
239 ('email' is provided by 'patchbomb' extension)
239 ('email' is provided by 'patchbomb' extension)
240 [255]
240 [30]
241 $ hg help disabled
241 $ hg help disabled
242 alias 'disabled' resolves to unknown command 'email'
242 alias 'disabled' resolves to unknown command 'email'
243
243
244 'email' is provided by the following extension:
244 'email' is provided by the following extension:
245
245
246 patchbomb command to send changesets as (a series of) patch emails
246 patchbomb command to send changesets as (a series of) patch emails
247
247
248 (use 'hg help extensions' for information on enabling extensions)
248 (use 'hg help extensions' for information on enabling extensions)
249
249
250
250
251 no definition
251 no definition
252
252
253 $ hg nodef
253 $ hg nodef
254 abort: no definition for alias 'nodefinition'
254 config error: no definition for alias 'nodefinition'
255 [255]
255 [30]
256 $ hg help nodef
256 $ hg help nodef
257 no definition for alias 'nodefinition'
257 no definition for alias 'nodefinition'
258
258
259
259
260 no closing quotation
260 no closing quotation
261
261
262 $ hg noclosing
262 $ hg noclosing
263 abort: error in definition for alias 'noclosingquotation': No closing quotation
263 config error: error in definition for alias 'noclosingquotation': No closing quotation
264 [255]
264 [30]
265 $ hg help noclosing
265 $ hg help noclosing
266 error in definition for alias 'noclosingquotation': No closing quotation
266 error in definition for alias 'noclosingquotation': No closing quotation
267
267
268 "--" in alias definition should be preserved
268 "--" in alias definition should be preserved
269
269
270 $ hg --config alias.dash='cat --' -R alias dash -r0
270 $ hg --config alias.dash='cat --' -R alias dash -r0
271 abort: -r0 not under root '$TESTTMP/alias'
271 abort: -r0 not under root '$TESTTMP/alias'
272 (consider using '--cwd alias')
272 (consider using '--cwd alias')
273 [255]
273 [255]
274
274
275 invalid options
275 invalid options
276
276
277 $ hg no--cwd
277 $ hg no--cwd
278 abort: error in definition for alias 'no--cwd': --cwd may only be given on the command line
278 config error: error in definition for alias 'no--cwd': --cwd may only be given on the command line
279 [255]
279 [30]
280 $ hg help no--cwd
280 $ hg help no--cwd
281 error in definition for alias 'no--cwd': --cwd may only be given on the
281 error in definition for alias 'no--cwd': --cwd may only be given on the
282 command line
282 command line
283 $ hg no-R
283 $ hg no-R
284 abort: error in definition for alias 'no-R': -R may only be given on the command line
284 config error: error in definition for alias 'no-R': -R may only be given on the command line
285 [255]
285 [30]
286 $ hg help no-R
286 $ hg help no-R
287 error in definition for alias 'no-R': -R may only be given on the command line
287 error in definition for alias 'no-R': -R may only be given on the command line
288 $ hg no--repo
288 $ hg no--repo
289 abort: error in definition for alias 'no--repo': --repo may only be given on the command line
289 config error: error in definition for alias 'no--repo': --repo may only be given on the command line
290 [255]
290 [30]
291 $ hg help no--repo
291 $ hg help no--repo
292 error in definition for alias 'no--repo': --repo may only be given on the
292 error in definition for alias 'no--repo': --repo may only be given on the
293 command line
293 command line
294 $ hg no--repository
294 $ hg no--repository
295 abort: error in definition for alias 'no--repository': --repository may only be given on the command line
295 config error: error in definition for alias 'no--repository': --repository may only be given on the command line
296 [255]
296 [30]
297 $ hg help no--repository
297 $ hg help no--repository
298 error in definition for alias 'no--repository': --repository may only be given
298 error in definition for alias 'no--repository': --repository may only be given
299 on the command line
299 on the command line
300 $ hg no--config
300 $ hg no--config
301 abort: error in definition for alias 'no--config': --config may only be given on the command line
301 config error: error in definition for alias 'no--config': --config may only be given on the command line
302 [255]
302 [30]
303 $ hg no --config alias.no='--repo elsewhere --cwd elsewhere status'
303 $ hg no --config alias.no='--repo elsewhere --cwd elsewhere status'
304 abort: error in definition for alias 'no': --repo/--cwd may only be given on the command line
304 config error: error in definition for alias 'no': --repo/--cwd may only be given on the command line
305 [255]
305 [30]
306 $ hg no --config alias.no='--repo elsewhere'
306 $ hg no --config alias.no='--repo elsewhere'
307 abort: error in definition for alias 'no': --repo may only be given on the command line
307 config error: error in definition for alias 'no': --repo may only be given on the command line
308 [255]
308 [30]
309
309
310 optional repository
310 optional repository
311
311
312 #if no-outer-repo
312 #if no-outer-repo
313 $ hg optionalrepo
313 $ hg optionalrepo
314 init
314 init
315 #endif
315 #endif
316 $ cd alias
316 $ cd alias
317 $ cat > .hg/hgrc <<EOF
317 $ cat > .hg/hgrc <<EOF
318 > [alias]
318 > [alias]
319 > myinit = init -q
319 > myinit = init -q
320 > EOF
320 > EOF
321 $ hg optionalrepo
321 $ hg optionalrepo
322 init -q
322 init -q
323
323
324 no usage
324 no usage
325
325
326 $ hg nousage
326 $ hg nousage
327 no rollback information available
327 no rollback information available
328 [1]
328 [1]
329
329
330 $ echo foo > foo
330 $ echo foo > foo
331 $ hg commit -Amfoo
331 $ hg commit -Amfoo
332 adding foo
332 adding foo
333
333
334 infer repository
334 infer repository
335
335
336 $ cd ..
336 $ cd ..
337
337
338 #if no-outer-repo
338 #if no-outer-repo
339 $ hg shortlog alias/foo
339 $ hg shortlog alias/foo
340 0 e63c23eaa88a | 1970-01-01 00:00 +0000
340 0 e63c23eaa88a | 1970-01-01 00:00 +0000
341 #endif
341 #endif
342
342
343 $ cd alias
343 $ cd alias
344
344
345 with opts
345 with opts
346
346
347 $ hg cleanst
347 $ hg cleanst
348 C foo
348 C foo
349
349
350
350
351 with opts and whitespace
351 with opts and whitespace
352
352
353 $ hg shortlog
353 $ hg shortlog
354 0 e63c23eaa88a | 1970-01-01 00:00 +0000
354 0 e63c23eaa88a | 1970-01-01 00:00 +0000
355
355
356 positional arguments
356 positional arguments
357
357
358 $ hg positional
358 $ hg positional
359 abort: too few arguments for command alias
359 abort: too few arguments for command alias
360 [255]
360 [255]
361 $ hg positional a
361 $ hg positional a
362 abort: too few arguments for command alias
362 abort: too few arguments for command alias
363 [255]
363 [255]
364 $ hg positional 'node|short' rev
364 $ hg positional 'node|short' rev
365 0 e63c23eaa88a | 1970-01-01 00:00 +0000
365 0 e63c23eaa88a | 1970-01-01 00:00 +0000
366
366
367 interaction with defaults
367 interaction with defaults
368
368
369 $ hg mylog
369 $ hg mylog
370 0:e63c23eaa88a
370 0:e63c23eaa88a
371 $ hg lognull
371 $ hg lognull
372 -1:000000000000
372 -1:000000000000
373
373
374
374
375 properly recursive
375 properly recursive
376
376
377 $ hg dln
377 $ hg dln
378 changeset: -1:0000000000000000000000000000000000000000
378 changeset: -1:0000000000000000000000000000000000000000
379 phase: public
379 phase: public
380 parent: -1:0000000000000000000000000000000000000000
380 parent: -1:0000000000000000000000000000000000000000
381 parent: -1:0000000000000000000000000000000000000000
381 parent: -1:0000000000000000000000000000000000000000
382 manifest: -1:0000000000000000000000000000000000000000
382 manifest: -1:0000000000000000000000000000000000000000
383 user:
383 user:
384 date: Thu Jan 01 00:00:00 1970 +0000
384 date: Thu Jan 01 00:00:00 1970 +0000
385 extra: branch=default
385 extra: branch=default
386
386
387
387
388
388
389 path expanding
389 path expanding
390
390
391 $ FOO=`pwd` hg put
391 $ FOO=`pwd` hg put
392 $ cat 0.diff
392 $ cat 0.diff
393 # HG changeset patch
393 # HG changeset patch
394 # User test
394 # User test
395 # Date 0 0
395 # Date 0 0
396 # Thu Jan 01 00:00:00 1970 +0000
396 # Thu Jan 01 00:00:00 1970 +0000
397 # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
397 # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
398 # Parent 0000000000000000000000000000000000000000
398 # Parent 0000000000000000000000000000000000000000
399 foo
399 foo
400
400
401 diff -r 000000000000 -r e63c23eaa88a foo
401 diff -r 000000000000 -r e63c23eaa88a foo
402 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
402 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
403 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
403 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
404 @@ -0,0 +1,1 @@
404 @@ -0,0 +1,1 @@
405 +foo
405 +foo
406
406
407
407
408 simple shell aliases
408 simple shell aliases
409
409
410 $ hg blank
410 $ hg blank
411
411
412 $ hg blank foo
412 $ hg blank foo
413
413
414 $ hg self
414 $ hg self
415 self
415 self
416 $ hg echoall
416 $ hg echoall
417
417
418 $ hg echoall foo
418 $ hg echoall foo
419 foo
419 foo
420 $ hg echoall 'test $2' foo
420 $ hg echoall 'test $2' foo
421 test $2 foo
421 test $2 foo
422 $ hg echoall 'test $@' foo '$@'
422 $ hg echoall 'test $@' foo '$@'
423 test $@ foo $@
423 test $@ foo $@
424 $ hg echoall 'test "$@"' foo '"$@"'
424 $ hg echoall 'test "$@"' foo '"$@"'
425 test "$@" foo "$@"
425 test "$@" foo "$@"
426 $ hg echo1 foo bar baz
426 $ hg echo1 foo bar baz
427 foo
427 foo
428 $ hg echo2 foo bar baz
428 $ hg echo2 foo bar baz
429 bar
429 bar
430 $ hg echo13 foo bar baz test
430 $ hg echo13 foo bar baz test
431 foo baz
431 foo baz
432 $ hg echo2 foo
432 $ hg echo2 foo
433
433
434 $ hg echotokens
434 $ hg echotokens
435
435
436 $ hg echotokens foo 'bar $1 baz'
436 $ hg echotokens foo 'bar $1 baz'
437 foo
437 foo
438 bar $1 baz
438 bar $1 baz
439 $ hg echotokens 'test $2' foo
439 $ hg echotokens 'test $2' foo
440 test $2
440 test $2
441 foo
441 foo
442 $ hg echotokens 'test $@' foo '$@'
442 $ hg echotokens 'test $@' foo '$@'
443 test $@
443 test $@
444 foo
444 foo
445 $@
445 $@
446 $ hg echotokens 'test "$@"' foo '"$@"'
446 $ hg echotokens 'test "$@"' foo '"$@"'
447 test "$@"
447 test "$@"
448 foo
448 foo
449 "$@"
449 "$@"
450 $ echo bar > bar
450 $ echo bar > bar
451 $ hg commit -qA -m bar
451 $ hg commit -qA -m bar
452 $ hg count .
452 $ hg count .
453 1
453 1
454 $ hg count 'branch(default)'
454 $ hg count 'branch(default)'
455 2
455 2
456 $ hg mcount -r '"branch(default)"'
456 $ hg mcount -r '"branch(default)"'
457 2
457 2
458
458
459 $ hg tglog
459 $ hg tglog
460 @ 1:042423737847: 'bar'
460 @ 1:042423737847: 'bar'
461 |
461 |
462 o 0:e63c23eaa88a: 'foo'
462 o 0:e63c23eaa88a: 'foo'
463
463
464
464
465
465
466 shadowing
466 shadowing
467
467
468 $ hg i
468 $ hg i
469 hg: command 'i' is ambiguous:
469 hg: command 'i' is ambiguous:
470 idalias idaliaslong idaliasshell identify import incoming init
470 idalias idaliaslong idaliasshell identify import incoming init
471 [255]
471 [255]
472 $ hg id
472 $ hg id
473 042423737847 tip
473 042423737847 tip
474 $ hg ida
474 $ hg ida
475 hg: command 'ida' is ambiguous:
475 hg: command 'ida' is ambiguous:
476 idalias idaliaslong idaliasshell
476 idalias idaliaslong idaliasshell
477 [255]
477 [255]
478 $ hg idalias
478 $ hg idalias
479 042423737847 tip
479 042423737847 tip
480 $ hg idaliasl
480 $ hg idaliasl
481 042423737847 tip
481 042423737847 tip
482 $ hg idaliass
482 $ hg idaliass
483 test
483 test
484 $ hg parentsshell
484 $ hg parentsshell
485 hg: command 'parentsshell' is ambiguous:
485 hg: command 'parentsshell' is ambiguous:
486 parentsshell1 parentsshell2
486 parentsshell1 parentsshell2
487 [255]
487 [255]
488 $ hg parentsshell1
488 $ hg parentsshell1
489 one
489 one
490 $ hg parentsshell2
490 $ hg parentsshell2
491 two
491 two
492
492
493
493
494 shell aliases with global options
494 shell aliases with global options
495
495
496 $ hg init sub
496 $ hg init sub
497 $ cd sub
497 $ cd sub
498 $ hg count 'branch(default)'
498 $ hg count 'branch(default)'
499 abort: unknown revision 'default'
499 abort: unknown revision 'default'
500 0
500 0
501 $ hg -v count 'branch(default)'
501 $ hg -v count 'branch(default)'
502 abort: unknown revision 'default'
502 abort: unknown revision 'default'
503 0
503 0
504 $ hg -R .. count 'branch(default)'
504 $ hg -R .. count 'branch(default)'
505 abort: unknown revision 'default'
505 abort: unknown revision 'default'
506 0
506 0
507 $ hg --cwd .. count 'branch(default)'
507 $ hg --cwd .. count 'branch(default)'
508 2
508 2
509 $ hg echoall --cwd ..
509 $ hg echoall --cwd ..
510
510
511
511
512 "--" passed to shell alias should be preserved
512 "--" passed to shell alias should be preserved
513
513
514 $ hg --config alias.printf='!printf "$@"' printf '%s %s %s\n' -- --cwd ..
514 $ hg --config alias.printf='!printf "$@"' printf '%s %s %s\n' -- --cwd ..
515 -- --cwd ..
515 -- --cwd ..
516
516
517 repo specific shell aliases
517 repo specific shell aliases
518
518
519 $ cat >> .hg/hgrc <<EOF
519 $ cat >> .hg/hgrc <<EOF
520 > [alias]
520 > [alias]
521 > subalias = !echo sub
521 > subalias = !echo sub
522 > EOF
522 > EOF
523 $ cat >> ../.hg/hgrc <<EOF
523 $ cat >> ../.hg/hgrc <<EOF
524 > [alias]
524 > [alias]
525 > mainalias = !echo main
525 > mainalias = !echo main
526 > EOF
526 > EOF
527
527
528
528
529 shell alias defined in current repo
529 shell alias defined in current repo
530
530
531 $ hg subalias
531 $ hg subalias
532 sub
532 sub
533 $ hg --cwd .. subalias > /dev/null
533 $ hg --cwd .. subalias > /dev/null
534 hg: unknown command 'subalias'
534 hg: unknown command 'subalias'
535 (did you mean idalias?)
535 (did you mean idalias?)
536 [255]
536 [255]
537 $ hg -R .. subalias > /dev/null
537 $ hg -R .. subalias > /dev/null
538 hg: unknown command 'subalias'
538 hg: unknown command 'subalias'
539 (did you mean idalias?)
539 (did you mean idalias?)
540 [255]
540 [255]
541
541
542
542
543 shell alias defined in other repo
543 shell alias defined in other repo
544
544
545 $ hg mainalias > /dev/null
545 $ hg mainalias > /dev/null
546 hg: unknown command 'mainalias'
546 hg: unknown command 'mainalias'
547 (did you mean idalias?)
547 (did you mean idalias?)
548 [255]
548 [255]
549 $ hg -R .. mainalias
549 $ hg -R .. mainalias
550 main
550 main
551 $ hg --cwd .. mainalias
551 $ hg --cwd .. mainalias
552 main
552 main
553
553
554 typos get useful suggestions
554 typos get useful suggestions
555 $ hg --cwd .. manalias
555 $ hg --cwd .. manalias
556 hg: unknown command 'manalias'
556 hg: unknown command 'manalias'
557 (did you mean one of idalias, mainalias, manifest?)
557 (did you mean one of idalias, mainalias, manifest?)
558 [255]
558 [255]
559
559
560 shell aliases with escaped $ chars
560 shell aliases with escaped $ chars
561
561
562 $ hg escaped1
562 $ hg escaped1
563 test$test
563 test$test
564 $ hg escaped2
564 $ hg escaped2
565 HGFOO is BAR
565 HGFOO is BAR
566 $ hg escaped3 HGFOO
566 $ hg escaped3 HGFOO
567 HGFOO is BAR
567 HGFOO is BAR
568 $ hg escaped4 test
568 $ hg escaped4 test
569 $0 $@
569 $0 $@
570
570
571 abbreviated name, which matches against both shell alias and the
571 abbreviated name, which matches against both shell alias and the
572 command provided extension, should be aborted.
572 command provided extension, should be aborted.
573
573
574 $ cat >> .hg/hgrc <<EOF
574 $ cat >> .hg/hgrc <<EOF
575 > [extensions]
575 > [extensions]
576 > hgext.rebase =
576 > hgext.rebase =
577 > EOF
577 > EOF
578 #if windows
578 #if windows
579 $ cat >> .hg/hgrc <<EOF
579 $ cat >> .hg/hgrc <<EOF
580 > [alias]
580 > [alias]
581 > rebate = !echo this is %HG_ARGS%
581 > rebate = !echo this is %HG_ARGS%
582 > EOF
582 > EOF
583 #else
583 #else
584 $ cat >> .hg/hgrc <<EOF
584 $ cat >> .hg/hgrc <<EOF
585 > [alias]
585 > [alias]
586 > rebate = !echo this is \$HG_ARGS
586 > rebate = !echo this is \$HG_ARGS
587 > EOF
587 > EOF
588 #endif
588 #endif
589 $ cat >> .hg/hgrc <<EOF
589 $ cat >> .hg/hgrc <<EOF
590 > rebate:doc = This is my alias which just prints something.
590 > rebate:doc = This is my alias which just prints something.
591 > rebate:help = [MYARGS]
591 > rebate:help = [MYARGS]
592 > EOF
592 > EOF
593 $ hg reba
593 $ hg reba
594 hg: command 'reba' is ambiguous:
594 hg: command 'reba' is ambiguous:
595 rebase rebate
595 rebase rebate
596 [255]
596 [255]
597 $ hg rebat
597 $ hg rebat
598 this is rebate
598 this is rebate
599 $ hg rebat --foo-bar
599 $ hg rebat --foo-bar
600 this is rebate --foo-bar
600 this is rebate --foo-bar
601
601
602 help for a shell alias
602 help for a shell alias
603
603
604 $ hg help -c | grep rebate
604 $ hg help -c | grep rebate
605 rebate This is my alias which just prints something.
605 rebate This is my alias which just prints something.
606 $ hg help rebate
606 $ hg help rebate
607 hg rebate [MYARGS]
607 hg rebate [MYARGS]
608
608
609 shell alias for: echo this is %HG_ARGS% (windows !)
609 shell alias for: echo this is %HG_ARGS% (windows !)
610 shell alias for: echo this is $HG_ARGS (no-windows !)
610 shell alias for: echo this is $HG_ARGS (no-windows !)
611
611
612 This is my alias which just prints something.
612 This is my alias which just prints something.
613
613
614 defined by:* (glob)
614 defined by:* (glob)
615 */* (glob) (?)
615 */* (glob) (?)
616 */* (glob) (?)
616 */* (glob) (?)
617 */* (glob) (?)
617 */* (glob) (?)
618
618
619 (some details hidden, use --verbose to show complete help)
619 (some details hidden, use --verbose to show complete help)
620
620
621 invalid character in user-specified help
621 invalid character in user-specified help
622
622
623 >>> with open('.hg/hgrc', 'ab') as f:
623 >>> with open('.hg/hgrc', 'ab') as f:
624 ... f.write(b'[alias]\n'
624 ... f.write(b'[alias]\n'
625 ... b'invaliddoc = log\n'
625 ... b'invaliddoc = log\n'
626 ... b'invaliddoc:doc = \xc3\xa9\n'
626 ... b'invaliddoc:doc = \xc3\xa9\n'
627 ... b'invalidhelp = log\n'
627 ... b'invalidhelp = log\n'
628 ... b'invalidhelp:help = \xc3\xa9\n') and None
628 ... b'invalidhelp:help = \xc3\xa9\n') and None
629 $ hg help invaliddoc
629 $ hg help invaliddoc
630 non-ASCII character in alias definition 'invaliddoc:doc'
630 non-ASCII character in alias definition 'invaliddoc:doc'
631 $ hg help invalidhelp
631 $ hg help invalidhelp
632 non-ASCII character in alias definition 'invalidhelp:help'
632 non-ASCII character in alias definition 'invalidhelp:help'
633 $ hg invaliddoc
633 $ hg invaliddoc
634 abort: non-ASCII character in alias definition 'invaliddoc:doc'
634 config error: non-ASCII character in alias definition 'invaliddoc:doc'
635 [255]
635 [30]
636 $ hg invalidhelp
636 $ hg invalidhelp
637 abort: non-ASCII character in alias definition 'invalidhelp:help'
637 config error: non-ASCII character in alias definition 'invalidhelp:help'
638 [255]
638 [30]
639
639
640 invalid arguments
640 invalid arguments
641
641
642 $ hg rt foo
642 $ hg rt foo
643 hg rt: invalid arguments
643 hg rt: invalid arguments
644 hg rt
644 hg rt
645
645
646 alias for: hg root
646 alias for: hg root
647
647
648 options:
648 options:
649
649
650 -T --template TEMPLATE display with template
650 -T --template TEMPLATE display with template
651
651
652 (use 'hg rt -h' to show more help)
652 (use 'hg rt -h' to show more help)
653 [255]
653 [255]
654
654
655 invalid global arguments for normal commands, aliases, and shell aliases
655 invalid global arguments for normal commands, aliases, and shell aliases
656
656
657 $ hg --invalid root
657 $ hg --invalid root
658 hg: option --invalid not recognized
658 hg: option --invalid not recognized
659 (use 'hg help -v' for a list of global options)
659 (use 'hg help -v' for a list of global options)
660 [255]
660 [255]
661 $ hg --invalid mylog
661 $ hg --invalid mylog
662 hg: option --invalid not recognized
662 hg: option --invalid not recognized
663 (use 'hg help -v' for a list of global options)
663 (use 'hg help -v' for a list of global options)
664 [255]
664 [255]
665 $ hg --invalid blank
665 $ hg --invalid blank
666 hg: option --invalid not recognized
666 hg: option --invalid not recognized
667 (use 'hg help -v' for a list of global options)
667 (use 'hg help -v' for a list of global options)
668 [255]
668 [255]
669
669
670 environment variable changes in alias commands
670 environment variable changes in alias commands
671
671
672 $ cat > $TESTTMP/expandalias.py <<EOF
672 $ cat > $TESTTMP/expandalias.py <<EOF
673 > import os
673 > import os
674 > from mercurial import cmdutil, commands, registrar
674 > from mercurial import cmdutil, commands, registrar
675 > cmdtable = {}
675 > cmdtable = {}
676 > command = registrar.command(cmdtable)
676 > command = registrar.command(cmdtable)
677 > @command(b'expandalias')
677 > @command(b'expandalias')
678 > def expandalias(ui, repo, name):
678 > def expandalias(ui, repo, name):
679 > alias = cmdutil.findcmd(name, commands.table)[1][0]
679 > alias = cmdutil.findcmd(name, commands.table)[1][0]
680 > ui.write(b'%s args: %s\n' % (name, b' '.join(alias.args)))
680 > ui.write(b'%s args: %s\n' % (name, b' '.join(alias.args)))
681 > os.environ['COUNT'] = '2'
681 > os.environ['COUNT'] = '2'
682 > ui.write(b'%s args: %s (with COUNT=2)\n' % (name, b' '.join(alias.args)))
682 > ui.write(b'%s args: %s (with COUNT=2)\n' % (name, b' '.join(alias.args)))
683 > EOF
683 > EOF
684
684
685 $ cat >> $HGRCPATH <<'EOF'
685 $ cat >> $HGRCPATH <<'EOF'
686 > [extensions]
686 > [extensions]
687 > expandalias = $TESTTMP/expandalias.py
687 > expandalias = $TESTTMP/expandalias.py
688 > [alias]
688 > [alias]
689 > showcount = log -T "$COUNT" -r .
689 > showcount = log -T "$COUNT" -r .
690 > EOF
690 > EOF
691
691
692 $ COUNT=1 hg expandalias showcount
692 $ COUNT=1 hg expandalias showcount
693 showcount args: -T 1 -r .
693 showcount args: -T 1 -r .
694 showcount args: -T 2 -r . (with COUNT=2)
694 showcount args: -T 2 -r . (with COUNT=2)
695
695
696 This should show id:
696 This should show id:
697
697
698 $ hg --config alias.log='id' log
698 $ hg --config alias.log='id' log
699 000000000000 tip
699 000000000000 tip
700
700
701 This shouldn't:
701 This shouldn't:
702
702
703 $ hg --config alias.log='id' history
703 $ hg --config alias.log='id' history
704
704
705 $ cd ../..
705 $ cd ../..
706
706
707 return code of command and shell aliases:
707 return code of command and shell aliases:
708
708
709 $ hg mycommit -R alias
709 $ hg mycommit -R alias
710 nothing changed
710 nothing changed
711 [1]
711 [1]
712 $ hg exit1
712 $ hg exit1
713 [1]
713 [1]
714
714
715 #if no-outer-repo
715 #if no-outer-repo
716 $ hg root
716 $ hg root
717 abort: no repository found in '$TESTTMP' (.hg not found)
717 abort: no repository found in '$TESTTMP' (.hg not found)
718 [10]
718 [10]
719 $ hg --config alias.hgroot='!hg root' hgroot
719 $ hg --config alias.hgroot='!hg root' hgroot
720 abort: no repository found in '$TESTTMP' (.hg not found)
720 abort: no repository found in '$TESTTMP' (.hg not found)
721 [10]
721 [10]
722 #endif
722 #endif
General Comments 0
You need to be logged in to leave comments. Login now