##// END OF EJS Templates
errors: remove trailing "!" in messages about bad top-level args...
Martin von Zweigbergk -
r46521:ca39c450 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.Abort(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.Abort(
1177 raise error.Abort(
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.RepoError(
1198 raise error.RepoError(
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,221 +1,221 b''
1 test command parsing and dispatch
1 test command parsing and dispatch
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5
5
6 Redundant options used to crash (issue436):
6 Redundant options used to crash (issue436):
7 $ hg -v log -v
7 $ hg -v log -v
8 $ hg -v log -v x
8 $ hg -v log -v x
9
9
10 $ echo a > a
10 $ echo a > a
11 $ hg ci -Ama
11 $ hg ci -Ama
12 adding a
12 adding a
13
13
14 Missing arg:
14 Missing arg:
15
15
16 $ hg cat
16 $ hg cat
17 hg cat: invalid arguments
17 hg cat: invalid arguments
18 hg cat [OPTION]... FILE...
18 hg cat [OPTION]... FILE...
19
19
20 output the current or given revision of files
20 output the current or given revision of files
21
21
22 options ([+] can be repeated):
22 options ([+] can be repeated):
23
23
24 -o --output FORMAT print output to file with formatted name
24 -o --output FORMAT print output to file with formatted name
25 -r --rev REV print the given revision
25 -r --rev REV print the given revision
26 --decode apply any matching decode filter
26 --decode apply any matching decode filter
27 -I --include PATTERN [+] include names matching the given patterns
27 -I --include PATTERN [+] include names matching the given patterns
28 -X --exclude PATTERN [+] exclude names matching the given patterns
28 -X --exclude PATTERN [+] exclude names matching the given patterns
29 -T --template TEMPLATE display with template
29 -T --template TEMPLATE display with template
30
30
31 (use 'hg cat -h' to show more help)
31 (use 'hg cat -h' to show more help)
32 [255]
32 [255]
33
33
34 Missing parameter for early option:
34 Missing parameter for early option:
35
35
36 $ hg log -R 2>&1 | grep 'hg log'
36 $ hg log -R 2>&1 | grep 'hg log'
37 hg log: option -R requires argument
37 hg log: option -R requires argument
38 hg log [OPTION]... [FILE]
38 hg log [OPTION]... [FILE]
39 (use 'hg log -h' to show more help)
39 (use 'hg log -h' to show more help)
40
40
41 "--" may be an option value:
41 "--" may be an option value:
42
42
43 $ hg -R -- log
43 $ hg -R -- log
44 abort: repository -- not found
44 abort: repository -- not found
45 [255]
45 [255]
46 $ hg log -R --
46 $ hg log -R --
47 abort: repository -- not found
47 abort: repository -- not found
48 [255]
48 [255]
49 $ hg log -T --
49 $ hg log -T --
50 -- (no-eol)
50 -- (no-eol)
51 $ hg log -T -- -k nomatch
51 $ hg log -T -- -k nomatch
52
52
53 Parsing of early options should stop at "--":
53 Parsing of early options should stop at "--":
54
54
55 $ hg cat -- --config=hooks.pre-cat=false
55 $ hg cat -- --config=hooks.pre-cat=false
56 --config=hooks.pre-cat=false: no such file in rev cb9a9f314b8b
56 --config=hooks.pre-cat=false: no such file in rev cb9a9f314b8b
57 [1]
57 [1]
58 $ hg cat -- --debugger
58 $ hg cat -- --debugger
59 --debugger: no such file in rev cb9a9f314b8b
59 --debugger: no such file in rev cb9a9f314b8b
60 [1]
60 [1]
61
61
62 Unparsable form of early options:
62 Unparsable form of early options:
63
63
64 $ hg cat --debugg
64 $ hg cat --debugg
65 abort: option --debugger may not be abbreviated!
65 abort: option --debugger may not be abbreviated
66 [255]
66 [255]
67
67
68 Parsing failure of early options should be detected before executing the
68 Parsing failure of early options should be detected before executing the
69 command:
69 command:
70
70
71 $ hg log -b '--config=hooks.pre-log=false' default
71 $ hg log -b '--config=hooks.pre-log=false' default
72 abort: option --config may not be abbreviated!
72 abort: option --config may not be abbreviated
73 [255]
73 [255]
74 $ hg log -b -R. default
74 $ hg log -b -R. default
75 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
75 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo
76 [255]
76 [255]
77 $ hg log --cwd .. -b --cwd=. default
77 $ hg log --cwd .. -b --cwd=. default
78 abort: option --cwd may not be abbreviated!
78 abort: option --cwd may not be abbreviated
79 [255]
79 [255]
80
80
81 However, we can't prevent it from loading extensions and configs:
81 However, we can't prevent it from loading extensions and configs:
82
82
83 $ cat <<EOF > bad.py
83 $ cat <<EOF > bad.py
84 > raise Exception('bad')
84 > raise Exception('bad')
85 > EOF
85 > EOF
86 $ hg log -b '--config=extensions.bad=bad.py' default
86 $ hg log -b '--config=extensions.bad=bad.py' default
87 *** failed to import extension bad from bad.py: bad
87 *** failed to import extension bad from bad.py: bad
88 abort: option --config may not be abbreviated!
88 abort: option --config may not be abbreviated
89 [255]
89 [255]
90
90
91 $ mkdir -p badrepo/.hg
91 $ mkdir -p badrepo/.hg
92 $ echo 'invalid-syntax' > badrepo/.hg/hgrc
92 $ echo 'invalid-syntax' > badrepo/.hg/hgrc
93 $ hg log -b -Rbadrepo default
93 $ hg log -b -Rbadrepo default
94 config error at badrepo/.hg/hgrc:1: invalid-syntax
94 config error at badrepo/.hg/hgrc:1: invalid-syntax
95 [30]
95 [30]
96
96
97 $ hg log -b --cwd=inexistent default
97 $ hg log -b --cwd=inexistent default
98 abort: $ENOENT$: 'inexistent'
98 abort: $ENOENT$: 'inexistent'
99 [255]
99 [255]
100
100
101 $ hg log -b '--config=ui.traceback=yes' 2>&1 | grep '^Traceback'
101 $ hg log -b '--config=ui.traceback=yes' 2>&1 | grep '^Traceback'
102 Traceback (most recent call last):
102 Traceback (most recent call last):
103 $ hg log -b '--config=profiling.enabled=yes' 2>&1 | grep -i sample
103 $ hg log -b '--config=profiling.enabled=yes' 2>&1 | grep -i sample
104 Sample count: .*|No samples recorded\. (re)
104 Sample count: .*|No samples recorded\. (re)
105
105
106 Early options can't be specified in [aliases] and [defaults] because they are
106 Early options can't be specified in [aliases] and [defaults] because they are
107 applied before the command name is resolved:
107 applied before the command name is resolved:
108
108
109 $ hg log -b '--config=alias.log=log --config=hooks.pre-log=false'
109 $ hg log -b '--config=alias.log=log --config=hooks.pre-log=false'
110 hg log: option -b not recognized
110 hg log: option -b not recognized
111 error in definition for alias 'log': --config may only be given on the command
111 error in definition for alias 'log': --config may only be given on the command
112 line
112 line
113 [255]
113 [255]
114
114
115 $ hg log -b '--config=defaults.log=--config=hooks.pre-log=false'
115 $ hg log -b '--config=defaults.log=--config=hooks.pre-log=false'
116 abort: option --config may not be abbreviated!
116 abort: option --config may not be abbreviated
117 [255]
117 [255]
118
118
119 Shell aliases bypass any command parsing rules but for the early one:
119 Shell aliases bypass any command parsing rules but for the early one:
120
120
121 $ hg log -b '--config=alias.log=!echo howdy'
121 $ hg log -b '--config=alias.log=!echo howdy'
122 howdy
122 howdy
123
123
124 Early options must come first if HGPLAIN=+strictflags is specified:
124 Early options must come first if HGPLAIN=+strictflags is specified:
125 (BUG: chg cherry-picks early options to pass them as a server command)
125 (BUG: chg cherry-picks early options to pass them as a server command)
126
126
127 #if no-chg
127 #if no-chg
128 $ HGPLAIN=+strictflags hg log -b --config='hooks.pre-log=false' default
128 $ HGPLAIN=+strictflags hg log -b --config='hooks.pre-log=false' default
129 abort: unknown revision '--config=hooks.pre-log=false'
129 abort: unknown revision '--config=hooks.pre-log=false'
130 [255]
130 [255]
131 $ HGPLAIN=+strictflags hg log -b -R. default
131 $ HGPLAIN=+strictflags hg log -b -R. default
132 abort: unknown revision '-R.'
132 abort: unknown revision '-R.'
133 [255]
133 [255]
134 $ HGPLAIN=+strictflags hg log -b --cwd=. default
134 $ HGPLAIN=+strictflags hg log -b --cwd=. default
135 abort: unknown revision '--cwd=.'
135 abort: unknown revision '--cwd=.'
136 [255]
136 [255]
137 #endif
137 #endif
138 $ HGPLAIN=+strictflags hg log -b --debugger default
138 $ HGPLAIN=+strictflags hg log -b --debugger default
139 abort: unknown revision '--debugger'
139 abort: unknown revision '--debugger'
140 [255]
140 [255]
141 $ HGPLAIN=+strictflags hg log -b --config='alias.log=!echo pwned' default
141 $ HGPLAIN=+strictflags hg log -b --config='alias.log=!echo pwned' default
142 abort: unknown revision '--config=alias.log=!echo pwned'
142 abort: unknown revision '--config=alias.log=!echo pwned'
143 [255]
143 [255]
144
144
145 $ HGPLAIN=+strictflags hg log --config='hooks.pre-log=false' -b default
145 $ HGPLAIN=+strictflags hg log --config='hooks.pre-log=false' -b default
146 abort: option --config may not be abbreviated!
146 abort: option --config may not be abbreviated
147 [255]
147 [255]
148 $ HGPLAIN=+strictflags hg log -q --cwd=.. -b default
148 $ HGPLAIN=+strictflags hg log -q --cwd=.. -b default
149 abort: option --cwd may not be abbreviated!
149 abort: option --cwd may not be abbreviated
150 [255]
150 [255]
151 $ HGPLAIN=+strictflags hg log -q -R . -b default
151 $ HGPLAIN=+strictflags hg log -q -R . -b default
152 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
152 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo
153 [255]
153 [255]
154
154
155 $ HGPLAIN=+strictflags hg --config='hooks.pre-log=false' log -b default
155 $ HGPLAIN=+strictflags hg --config='hooks.pre-log=false' log -b default
156 abort: pre-log hook exited with status 1
156 abort: pre-log hook exited with status 1
157 [255]
157 [255]
158 $ HGPLAIN=+strictflags hg --cwd .. -q -Ra log -b default
158 $ HGPLAIN=+strictflags hg --cwd .. -q -Ra log -b default
159 0:cb9a9f314b8b
159 0:cb9a9f314b8b
160 $ HGPLAIN=+strictflags hg --cwd .. -q --repository a log -b default
160 $ HGPLAIN=+strictflags hg --cwd .. -q --repository a log -b default
161 0:cb9a9f314b8b
161 0:cb9a9f314b8b
162 $ HGPLAIN=+strictflags hg --cwd .. -q --repo a log -b default
162 $ HGPLAIN=+strictflags hg --cwd .. -q --repo a log -b default
163 0:cb9a9f314b8b
163 0:cb9a9f314b8b
164
164
165 For compatibility reasons, HGPLAIN=+strictflags is not enabled by plain HGPLAIN:
165 For compatibility reasons, HGPLAIN=+strictflags is not enabled by plain HGPLAIN:
166
166
167 $ HGPLAIN= hg log --config='hooks.pre-log=false' -b default
167 $ HGPLAIN= hg log --config='hooks.pre-log=false' -b default
168 abort: pre-log hook exited with status 1
168 abort: pre-log hook exited with status 1
169 [255]
169 [255]
170 $ HGPLAINEXCEPT= hg log --cwd .. -q -Ra -b default
170 $ HGPLAINEXCEPT= hg log --cwd .. -q -Ra -b default
171 0:cb9a9f314b8b
171 0:cb9a9f314b8b
172
172
173 [defaults]
173 [defaults]
174
174
175 $ hg cat a
175 $ hg cat a
176 a
176 a
177 $ cat >> $HGRCPATH <<EOF
177 $ cat >> $HGRCPATH <<EOF
178 > [defaults]
178 > [defaults]
179 > cat = -r null
179 > cat = -r null
180 > EOF
180 > EOF
181 $ hg cat a
181 $ hg cat a
182 a: no such file in rev 000000000000
182 a: no such file in rev 000000000000
183 [1]
183 [1]
184
184
185 $ cd "$TESTTMP"
185 $ cd "$TESTTMP"
186
186
187 OSError "No such file or directory" / "The system cannot find the path
187 OSError "No such file or directory" / "The system cannot find the path
188 specified" should include filename even when it is empty
188 specified" should include filename even when it is empty
189
189
190 $ hg -R a archive ''
190 $ hg -R a archive ''
191 abort: $ENOENT$: '' (no-windows !)
191 abort: $ENOENT$: '' (no-windows !)
192 abort: $ENOTDIR$: '' (windows !)
192 abort: $ENOTDIR$: '' (windows !)
193 [255]
193 [255]
194
194
195 #if no-outer-repo
195 #if no-outer-repo
196
196
197 No repo:
197 No repo:
198
198
199 $ hg cat
199 $ hg cat
200 abort: no repository found in '$TESTTMP' (.hg not found)
200 abort: no repository found in '$TESTTMP' (.hg not found)
201 [255]
201 [255]
202
202
203 #endif
203 #endif
204
204
205 #if rmcwd
205 #if rmcwd
206
206
207 Current directory removed:
207 Current directory removed:
208
208
209 $ mkdir $TESTTMP/repo1
209 $ mkdir $TESTTMP/repo1
210 $ cd $TESTTMP/repo1
210 $ cd $TESTTMP/repo1
211 $ rm -rf $TESTTMP/repo1
211 $ rm -rf $TESTTMP/repo1
212
212
213 The output could be one of the following and something else:
213 The output could be one of the following and something else:
214 chg: abort: failed to getcwd (errno = *) (glob)
214 chg: abort: failed to getcwd (errno = *) (glob)
215 abort: error getting current working directory: * (glob)
215 abort: error getting current working directory: * (glob)
216 sh: 0: getcwd() failed: $ENOENT$
216 sh: 0: getcwd() failed: $ENOENT$
217 Since the exact behavior depends on the shell, only check it returns non-zero.
217 Since the exact behavior depends on the shell, only check it returns non-zero.
218 $ HGDEMANDIMPORT=disable hg version -q 2>/dev/null || false
218 $ HGDEMANDIMPORT=disable hg version -q 2>/dev/null || false
219 [1]
219 [1]
220
220
221 #endif
221 #endif
@@ -1,562 +1,562 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo a > a
3 $ echo a > a
4 $ hg ci -A -d'1 0' -m a
4 $ hg ci -A -d'1 0' -m a
5 adding a
5 adding a
6
6
7 $ cd ..
7 $ cd ..
8
8
9 $ hg init b
9 $ hg init b
10 $ cd b
10 $ cd b
11 $ echo b > b
11 $ echo b > b
12 $ hg ci -A -d'1 0' -m b
12 $ hg ci -A -d'1 0' -m b
13 adding b
13 adding b
14
14
15 $ cd ..
15 $ cd ..
16
16
17 $ hg clone a c
17 $ hg clone a c
18 updating to branch default
18 updating to branch default
19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 $ cd c
20 $ cd c
21 $ cat >> .hg/hgrc <<EOF
21 $ cat >> .hg/hgrc <<EOF
22 > [paths]
22 > [paths]
23 > relative = ../a
23 > relative = ../a
24 > EOF
24 > EOF
25 $ hg pull -f ../b
25 $ hg pull -f ../b
26 pulling from ../b
26 pulling from ../b
27 searching for changes
27 searching for changes
28 warning: repository is unrelated
28 warning: repository is unrelated
29 requesting all changes
29 requesting all changes
30 adding changesets
30 adding changesets
31 adding manifests
31 adding manifests
32 adding file changes
32 adding file changes
33 added 1 changesets with 1 changes to 1 files (+1 heads)
33 added 1 changesets with 1 changes to 1 files (+1 heads)
34 new changesets b6c483daf290
34 new changesets b6c483daf290
35 (run 'hg heads' to see heads, 'hg merge' to merge)
35 (run 'hg heads' to see heads, 'hg merge' to merge)
36 $ hg merge
36 $ hg merge
37 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
37 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
38 (branch merge, don't forget to commit)
38 (branch merge, don't forget to commit)
39
39
40 $ cd ..
40 $ cd ..
41
41
42 Testing -R/--repository:
42 Testing -R/--repository:
43
43
44 $ hg -R a tip
44 $ hg -R a tip
45 changeset: 0:8580ff50825a
45 changeset: 0:8580ff50825a
46 tag: tip
46 tag: tip
47 user: test
47 user: test
48 date: Thu Jan 01 00:00:01 1970 +0000
48 date: Thu Jan 01 00:00:01 1970 +0000
49 summary: a
49 summary: a
50
50
51 $ hg --repository b tip
51 $ hg --repository b tip
52 changeset: 0:b6c483daf290
52 changeset: 0:b6c483daf290
53 tag: tip
53 tag: tip
54 user: test
54 user: test
55 date: Thu Jan 01 00:00:01 1970 +0000
55 date: Thu Jan 01 00:00:01 1970 +0000
56 summary: b
56 summary: b
57
57
58
58
59 -R with a URL:
59 -R with a URL:
60
60
61 $ hg -R file:a identify
61 $ hg -R file:a identify
62 8580ff50825a tip
62 8580ff50825a tip
63 $ hg -R file://localhost/`pwd`/a/ identify
63 $ hg -R file://localhost/`pwd`/a/ identify
64 8580ff50825a tip
64 8580ff50825a tip
65
65
66 -R with path aliases:
66 -R with path aliases:
67
67
68 $ cd c
68 $ cd c
69 $ hg -R default identify
69 $ hg -R default identify
70 8580ff50825a tip
70 8580ff50825a tip
71 $ hg -R relative identify
71 $ hg -R relative identify
72 8580ff50825a tip
72 8580ff50825a tip
73 $ echo '[paths]' >> $HGRCPATH
73 $ echo '[paths]' >> $HGRCPATH
74 $ echo 'relativetohome = a' >> $HGRCPATH
74 $ echo 'relativetohome = a' >> $HGRCPATH
75 $ HOME=`pwd`/../ hg -R relativetohome identify
75 $ HOME=`pwd`/../ hg -R relativetohome identify
76 8580ff50825a tip
76 8580ff50825a tip
77 $ cd ..
77 $ cd ..
78
78
79 #if no-outer-repo
79 #if no-outer-repo
80
80
81 Implicit -R:
81 Implicit -R:
82
82
83 $ hg ann a/a
83 $ hg ann a/a
84 0: a
84 0: a
85 $ hg ann a/a a/a
85 $ hg ann a/a a/a
86 0: a
86 0: a
87 $ hg ann a/a b/b
87 $ hg ann a/a b/b
88 abort: no repository found in '$TESTTMP' (.hg not found)
88 abort: no repository found in '$TESTTMP' (.hg not found)
89 [255]
89 [255]
90 $ hg -R b ann a/a
90 $ hg -R b ann a/a
91 abort: a/a not under root '$TESTTMP/b'
91 abort: a/a not under root '$TESTTMP/b'
92 (consider using '--cwd b')
92 (consider using '--cwd b')
93 [255]
93 [255]
94 $ hg log
94 $ hg log
95 abort: no repository found in '$TESTTMP' (.hg not found)
95 abort: no repository found in '$TESTTMP' (.hg not found)
96 [255]
96 [255]
97
97
98 #endif
98 #endif
99
99
100 Abbreviation of long option:
100 Abbreviation of long option:
101
101
102 $ hg --repo c tip
102 $ hg --repo c tip
103 changeset: 1:b6c483daf290
103 changeset: 1:b6c483daf290
104 tag: tip
104 tag: tip
105 parent: -1:000000000000
105 parent: -1:000000000000
106 user: test
106 user: test
107 date: Thu Jan 01 00:00:01 1970 +0000
107 date: Thu Jan 01 00:00:01 1970 +0000
108 summary: b
108 summary: b
109
109
110
110
111 earlygetopt with duplicate options (36d23de02da1):
111 earlygetopt with duplicate options (36d23de02da1):
112
112
113 $ hg --cwd a --cwd b --cwd c tip
113 $ hg --cwd a --cwd b --cwd c tip
114 changeset: 1:b6c483daf290
114 changeset: 1:b6c483daf290
115 tag: tip
115 tag: tip
116 parent: -1:000000000000
116 parent: -1:000000000000
117 user: test
117 user: test
118 date: Thu Jan 01 00:00:01 1970 +0000
118 date: Thu Jan 01 00:00:01 1970 +0000
119 summary: b
119 summary: b
120
120
121 $ hg --repo c --repository b -R a tip
121 $ hg --repo c --repository b -R a tip
122 changeset: 0:8580ff50825a
122 changeset: 0:8580ff50825a
123 tag: tip
123 tag: tip
124 user: test
124 user: test
125 date: Thu Jan 01 00:00:01 1970 +0000
125 date: Thu Jan 01 00:00:01 1970 +0000
126 summary: a
126 summary: a
127
127
128
128
129 earlygetopt short option without following space:
129 earlygetopt short option without following space:
130
130
131 $ hg -q -Rb tip
131 $ hg -q -Rb tip
132 0:b6c483daf290
132 0:b6c483daf290
133
133
134 earlygetopt with illegal abbreviations:
134 earlygetopt with illegal abbreviations:
135
135
136 $ hg --confi "foo.bar=baz"
136 $ hg --confi "foo.bar=baz"
137 abort: option --config may not be abbreviated!
137 abort: option --config may not be abbreviated
138 [255]
138 [255]
139 $ hg --cw a tip
139 $ hg --cw a tip
140 abort: option --cwd may not be abbreviated!
140 abort: option --cwd may not be abbreviated
141 [255]
141 [255]
142 $ hg --rep a tip
142 $ hg --rep a tip
143 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
143 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo
144 [255]
144 [255]
145 $ hg --repositor a tip
145 $ hg --repositor a tip
146 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
146 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo
147 [255]
147 [255]
148 $ hg -qR a tip
148 $ hg -qR a tip
149 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
149 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo
150 [255]
150 [255]
151 $ hg -qRa tip
151 $ hg -qRa tip
152 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo!
152 abort: option -R has to be separated from other options (e.g. not -qR) and --repository may only be abbreviated as --repo
153 [255]
153 [255]
154
154
155 Testing --cwd:
155 Testing --cwd:
156
156
157 $ hg --cwd a parents
157 $ hg --cwd a parents
158 changeset: 0:8580ff50825a
158 changeset: 0:8580ff50825a
159 tag: tip
159 tag: tip
160 user: test
160 user: test
161 date: Thu Jan 01 00:00:01 1970 +0000
161 date: Thu Jan 01 00:00:01 1970 +0000
162 summary: a
162 summary: a
163
163
164
164
165 Testing -y/--noninteractive - just be sure it is parsed:
165 Testing -y/--noninteractive - just be sure it is parsed:
166
166
167 $ hg --cwd a tip -q --noninteractive
167 $ hg --cwd a tip -q --noninteractive
168 0:8580ff50825a
168 0:8580ff50825a
169 $ hg --cwd a tip -q -y
169 $ hg --cwd a tip -q -y
170 0:8580ff50825a
170 0:8580ff50825a
171
171
172 Testing -q/--quiet:
172 Testing -q/--quiet:
173
173
174 $ hg -R a -q tip
174 $ hg -R a -q tip
175 0:8580ff50825a
175 0:8580ff50825a
176 $ hg -R b -q tip
176 $ hg -R b -q tip
177 0:b6c483daf290
177 0:b6c483daf290
178 $ hg -R c --quiet parents
178 $ hg -R c --quiet parents
179 0:8580ff50825a
179 0:8580ff50825a
180 1:b6c483daf290
180 1:b6c483daf290
181
181
182 Testing -v/--verbose:
182 Testing -v/--verbose:
183
183
184 $ hg --cwd c head -v
184 $ hg --cwd c head -v
185 changeset: 1:b6c483daf290
185 changeset: 1:b6c483daf290
186 tag: tip
186 tag: tip
187 parent: -1:000000000000
187 parent: -1:000000000000
188 user: test
188 user: test
189 date: Thu Jan 01 00:00:01 1970 +0000
189 date: Thu Jan 01 00:00:01 1970 +0000
190 files: b
190 files: b
191 description:
191 description:
192 b
192 b
193
193
194
194
195 changeset: 0:8580ff50825a
195 changeset: 0:8580ff50825a
196 user: test
196 user: test
197 date: Thu Jan 01 00:00:01 1970 +0000
197 date: Thu Jan 01 00:00:01 1970 +0000
198 files: a
198 files: a
199 description:
199 description:
200 a
200 a
201
201
202
202
203 $ hg --cwd b tip --verbose
203 $ hg --cwd b tip --verbose
204 changeset: 0:b6c483daf290
204 changeset: 0:b6c483daf290
205 tag: tip
205 tag: tip
206 user: test
206 user: test
207 date: Thu Jan 01 00:00:01 1970 +0000
207 date: Thu Jan 01 00:00:01 1970 +0000
208 files: b
208 files: b
209 description:
209 description:
210 b
210 b
211
211
212
212
213
213
214 Testing --config:
214 Testing --config:
215
215
216 $ hg --cwd c --config paths.quuxfoo=bar paths | grep quuxfoo > /dev/null && echo quuxfoo
216 $ hg --cwd c --config paths.quuxfoo=bar paths | grep quuxfoo > /dev/null && echo quuxfoo
217 quuxfoo
217 quuxfoo
218 $ hg --cwd c --config '' tip -q
218 $ hg --cwd c --config '' tip -q
219 abort: malformed --config option: '' (use --config section.name=value)
219 abort: malformed --config option: '' (use --config section.name=value)
220 [255]
220 [255]
221 $ hg --cwd c --config a.b tip -q
221 $ hg --cwd c --config a.b tip -q
222 abort: malformed --config option: 'a.b' (use --config section.name=value)
222 abort: malformed --config option: 'a.b' (use --config section.name=value)
223 [255]
223 [255]
224 $ hg --cwd c --config a tip -q
224 $ hg --cwd c --config a tip -q
225 abort: malformed --config option: 'a' (use --config section.name=value)
225 abort: malformed --config option: 'a' (use --config section.name=value)
226 [255]
226 [255]
227 $ hg --cwd c --config a.= tip -q
227 $ hg --cwd c --config a.= tip -q
228 abort: malformed --config option: 'a.=' (use --config section.name=value)
228 abort: malformed --config option: 'a.=' (use --config section.name=value)
229 [255]
229 [255]
230 $ hg --cwd c --config .b= tip -q
230 $ hg --cwd c --config .b= tip -q
231 abort: malformed --config option: '.b=' (use --config section.name=value)
231 abort: malformed --config option: '.b=' (use --config section.name=value)
232 [255]
232 [255]
233
233
234 Testing --debug:
234 Testing --debug:
235
235
236 $ hg --cwd c log --debug
236 $ hg --cwd c log --debug
237 changeset: 1:b6c483daf2907ce5825c0bb50f5716226281cc1a
237 changeset: 1:b6c483daf2907ce5825c0bb50f5716226281cc1a
238 tag: tip
238 tag: tip
239 phase: public
239 phase: public
240 parent: -1:0000000000000000000000000000000000000000
240 parent: -1:0000000000000000000000000000000000000000
241 parent: -1:0000000000000000000000000000000000000000
241 parent: -1:0000000000000000000000000000000000000000
242 manifest: 1:23226e7a252cacdc2d99e4fbdc3653441056de49
242 manifest: 1:23226e7a252cacdc2d99e4fbdc3653441056de49
243 user: test
243 user: test
244 date: Thu Jan 01 00:00:01 1970 +0000
244 date: Thu Jan 01 00:00:01 1970 +0000
245 files+: b
245 files+: b
246 extra: branch=default
246 extra: branch=default
247 description:
247 description:
248 b
248 b
249
249
250
250
251 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
251 changeset: 0:8580ff50825a50c8f716709acdf8de0deddcd6ab
252 phase: public
252 phase: public
253 parent: -1:0000000000000000000000000000000000000000
253 parent: -1:0000000000000000000000000000000000000000
254 parent: -1:0000000000000000000000000000000000000000
254 parent: -1:0000000000000000000000000000000000000000
255 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
255 manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
256 user: test
256 user: test
257 date: Thu Jan 01 00:00:01 1970 +0000
257 date: Thu Jan 01 00:00:01 1970 +0000
258 files+: a
258 files+: a
259 extra: branch=default
259 extra: branch=default
260 description:
260 description:
261 a
261 a
262
262
263
263
264
264
265 Testing --traceback:
265 Testing --traceback:
266
266
267 #if no-chg
267 #if no-chg
268 $ hg --cwd c --config x --traceback id 2>&1 | grep -i 'traceback'
268 $ hg --cwd c --config x --traceback id 2>&1 | grep -i 'traceback'
269 Traceback (most recent call last):
269 Traceback (most recent call last):
270 Traceback (most recent call last): (py3 !)
270 Traceback (most recent call last): (py3 !)
271 #else
271 #else
272 Traceback for '--config' errors not supported with chg.
272 Traceback for '--config' errors not supported with chg.
273 $ hg --cwd c --config x --traceback id 2>&1 | grep -i 'traceback'
273 $ hg --cwd c --config x --traceback id 2>&1 | grep -i 'traceback'
274 [1]
274 [1]
275 #endif
275 #endif
276
276
277 Testing --time:
277 Testing --time:
278
278
279 $ hg --cwd a --time id
279 $ hg --cwd a --time id
280 8580ff50825a tip
280 8580ff50825a tip
281 time: real * (glob)
281 time: real * (glob)
282
282
283 Testing --version:
283 Testing --version:
284
284
285 $ hg --version -q
285 $ hg --version -q
286 Mercurial Distributed SCM * (glob)
286 Mercurial Distributed SCM * (glob)
287
287
288 hide outer repo
288 hide outer repo
289 $ hg init
289 $ hg init
290
290
291 Testing -h/--help:
291 Testing -h/--help:
292
292
293 #if no-extraextensions
293 #if no-extraextensions
294
294
295 $ hg -h
295 $ hg -h
296 Mercurial Distributed SCM
296 Mercurial Distributed SCM
297
297
298 list of commands:
298 list of commands:
299
299
300 Repository creation:
300 Repository creation:
301
301
302 clone make a copy of an existing repository
302 clone make a copy of an existing repository
303 init create a new repository in the given directory
303 init create a new repository in the given directory
304
304
305 Remote repository management:
305 Remote repository management:
306
306
307 incoming show new changesets found in source
307 incoming show new changesets found in source
308 outgoing show changesets not found in the destination
308 outgoing show changesets not found in the destination
309 paths show aliases for remote repositories
309 paths show aliases for remote repositories
310 pull pull changes from the specified source
310 pull pull changes from the specified source
311 push push changes to the specified destination
311 push push changes to the specified destination
312 serve start stand-alone webserver
312 serve start stand-alone webserver
313
313
314 Change creation:
314 Change creation:
315
315
316 commit commit the specified files or all outstanding changes
316 commit commit the specified files or all outstanding changes
317
317
318 Change manipulation:
318 Change manipulation:
319
319
320 backout reverse effect of earlier changeset
320 backout reverse effect of earlier changeset
321 graft copy changes from other branches onto the current branch
321 graft copy changes from other branches onto the current branch
322 merge merge another revision into working directory
322 merge merge another revision into working directory
323
323
324 Change organization:
324 Change organization:
325
325
326 bookmarks create a new bookmark or list existing bookmarks
326 bookmarks create a new bookmark or list existing bookmarks
327 branch set or show the current branch name
327 branch set or show the current branch name
328 branches list repository named branches
328 branches list repository named branches
329 phase set or show the current phase name
329 phase set or show the current phase name
330 tag add one or more tags for the current or given revision
330 tag add one or more tags for the current or given revision
331 tags list repository tags
331 tags list repository tags
332
332
333 File content management:
333 File content management:
334
334
335 annotate show changeset information by line for each file
335 annotate show changeset information by line for each file
336 cat output the current or given revision of files
336 cat output the current or given revision of files
337 copy mark files as copied for the next commit
337 copy mark files as copied for the next commit
338 diff diff repository (or selected files)
338 diff diff repository (or selected files)
339 grep search for a pattern in specified files
339 grep search for a pattern in specified files
340
340
341 Change navigation:
341 Change navigation:
342
342
343 bisect subdivision search of changesets
343 bisect subdivision search of changesets
344 heads show branch heads
344 heads show branch heads
345 identify identify the working directory or specified revision
345 identify identify the working directory or specified revision
346 log show revision history of entire repository or files
346 log show revision history of entire repository or files
347
347
348 Working directory management:
348 Working directory management:
349
349
350 add add the specified files on the next commit
350 add add the specified files on the next commit
351 addremove add all new files, delete all missing files
351 addremove add all new files, delete all missing files
352 files list tracked files
352 files list tracked files
353 forget forget the specified files on the next commit
353 forget forget the specified files on the next commit
354 remove remove the specified files on the next commit
354 remove remove the specified files on the next commit
355 rename rename files; equivalent of copy + remove
355 rename rename files; equivalent of copy + remove
356 resolve redo merges or set/view the merge status of files
356 resolve redo merges or set/view the merge status of files
357 revert restore files to their checkout state
357 revert restore files to their checkout state
358 root print the root (top) of the current working directory
358 root print the root (top) of the current working directory
359 shelve save and set aside changes from the working directory
359 shelve save and set aside changes from the working directory
360 status show changed files in the working directory
360 status show changed files in the working directory
361 summary summarize working directory state
361 summary summarize working directory state
362 unshelve restore a shelved change to the working directory
362 unshelve restore a shelved change to the working directory
363 update update working directory (or switch revisions)
363 update update working directory (or switch revisions)
364
364
365 Change import/export:
365 Change import/export:
366
366
367 archive create an unversioned archive of a repository revision
367 archive create an unversioned archive of a repository revision
368 bundle create a bundle file
368 bundle create a bundle file
369 export dump the header and diffs for one or more changesets
369 export dump the header and diffs for one or more changesets
370 import import an ordered set of patches
370 import import an ordered set of patches
371 unbundle apply one or more bundle files
371 unbundle apply one or more bundle files
372
372
373 Repository maintenance:
373 Repository maintenance:
374
374
375 manifest output the current or given revision of the project manifest
375 manifest output the current or given revision of the project manifest
376 recover roll back an interrupted transaction
376 recover roll back an interrupted transaction
377 verify verify the integrity of the repository
377 verify verify the integrity of the repository
378
378
379 Help:
379 Help:
380
380
381 config show combined config settings from all hgrc files
381 config show combined config settings from all hgrc files
382 help show help for a given topic or a help overview
382 help show help for a given topic or a help overview
383 version output version and copyright information
383 version output version and copyright information
384
384
385 additional help topics:
385 additional help topics:
386
386
387 Mercurial identifiers:
387 Mercurial identifiers:
388
388
389 filesets Specifying File Sets
389 filesets Specifying File Sets
390 hgignore Syntax for Mercurial Ignore Files
390 hgignore Syntax for Mercurial Ignore Files
391 patterns File Name Patterns
391 patterns File Name Patterns
392 revisions Specifying Revisions
392 revisions Specifying Revisions
393 urls URL Paths
393 urls URL Paths
394
394
395 Mercurial output:
395 Mercurial output:
396
396
397 color Colorizing Outputs
397 color Colorizing Outputs
398 dates Date Formats
398 dates Date Formats
399 diffs Diff Formats
399 diffs Diff Formats
400 templating Template Usage
400 templating Template Usage
401
401
402 Mercurial configuration:
402 Mercurial configuration:
403
403
404 config Configuration Files
404 config Configuration Files
405 environment Environment Variables
405 environment Environment Variables
406 extensions Using Additional Features
406 extensions Using Additional Features
407 flags Command-line flags
407 flags Command-line flags
408 hgweb Configuring hgweb
408 hgweb Configuring hgweb
409 merge-tools Merge Tools
409 merge-tools Merge Tools
410 pager Pager Support
410 pager Pager Support
411
411
412 Concepts:
412 Concepts:
413
413
414 bundlespec Bundle File Formats
414 bundlespec Bundle File Formats
415 glossary Glossary
415 glossary Glossary
416 phases Working with Phases
416 phases Working with Phases
417 subrepos Subrepositories
417 subrepos Subrepositories
418
418
419 Miscellaneous:
419 Miscellaneous:
420
420
421 deprecated Deprecated Features
421 deprecated Deprecated Features
422 internals Technical implementation topics
422 internals Technical implementation topics
423 scripting Using Mercurial from scripts and automation
423 scripting Using Mercurial from scripts and automation
424
424
425 (use 'hg help -v' to show built-in aliases and global options)
425 (use 'hg help -v' to show built-in aliases and global options)
426
426
427 $ hg --help
427 $ hg --help
428 Mercurial Distributed SCM
428 Mercurial Distributed SCM
429
429
430 list of commands:
430 list of commands:
431
431
432 Repository creation:
432 Repository creation:
433
433
434 clone make a copy of an existing repository
434 clone make a copy of an existing repository
435 init create a new repository in the given directory
435 init create a new repository in the given directory
436
436
437 Remote repository management:
437 Remote repository management:
438
438
439 incoming show new changesets found in source
439 incoming show new changesets found in source
440 outgoing show changesets not found in the destination
440 outgoing show changesets not found in the destination
441 paths show aliases for remote repositories
441 paths show aliases for remote repositories
442 pull pull changes from the specified source
442 pull pull changes from the specified source
443 push push changes to the specified destination
443 push push changes to the specified destination
444 serve start stand-alone webserver
444 serve start stand-alone webserver
445
445
446 Change creation:
446 Change creation:
447
447
448 commit commit the specified files or all outstanding changes
448 commit commit the specified files or all outstanding changes
449
449
450 Change manipulation:
450 Change manipulation:
451
451
452 backout reverse effect of earlier changeset
452 backout reverse effect of earlier changeset
453 graft copy changes from other branches onto the current branch
453 graft copy changes from other branches onto the current branch
454 merge merge another revision into working directory
454 merge merge another revision into working directory
455
455
456 Change organization:
456 Change organization:
457
457
458 bookmarks create a new bookmark or list existing bookmarks
458 bookmarks create a new bookmark or list existing bookmarks
459 branch set or show the current branch name
459 branch set or show the current branch name
460 branches list repository named branches
460 branches list repository named branches
461 phase set or show the current phase name
461 phase set or show the current phase name
462 tag add one or more tags for the current or given revision
462 tag add one or more tags for the current or given revision
463 tags list repository tags
463 tags list repository tags
464
464
465 File content management:
465 File content management:
466
466
467 annotate show changeset information by line for each file
467 annotate show changeset information by line for each file
468 cat output the current or given revision of files
468 cat output the current or given revision of files
469 copy mark files as copied for the next commit
469 copy mark files as copied for the next commit
470 diff diff repository (or selected files)
470 diff diff repository (or selected files)
471 grep search for a pattern in specified files
471 grep search for a pattern in specified files
472
472
473 Change navigation:
473 Change navigation:
474
474
475 bisect subdivision search of changesets
475 bisect subdivision search of changesets
476 heads show branch heads
476 heads show branch heads
477 identify identify the working directory or specified revision
477 identify identify the working directory or specified revision
478 log show revision history of entire repository or files
478 log show revision history of entire repository or files
479
479
480 Working directory management:
480 Working directory management:
481
481
482 add add the specified files on the next commit
482 add add the specified files on the next commit
483 addremove add all new files, delete all missing files
483 addremove add all new files, delete all missing files
484 files list tracked files
484 files list tracked files
485 forget forget the specified files on the next commit
485 forget forget the specified files on the next commit
486 remove remove the specified files on the next commit
486 remove remove the specified files on the next commit
487 rename rename files; equivalent of copy + remove
487 rename rename files; equivalent of copy + remove
488 resolve redo merges or set/view the merge status of files
488 resolve redo merges or set/view the merge status of files
489 revert restore files to their checkout state
489 revert restore files to their checkout state
490 root print the root (top) of the current working directory
490 root print the root (top) of the current working directory
491 shelve save and set aside changes from the working directory
491 shelve save and set aside changes from the working directory
492 status show changed files in the working directory
492 status show changed files in the working directory
493 summary summarize working directory state
493 summary summarize working directory state
494 unshelve restore a shelved change to the working directory
494 unshelve restore a shelved change to the working directory
495 update update working directory (or switch revisions)
495 update update working directory (or switch revisions)
496
496
497 Change import/export:
497 Change import/export:
498
498
499 archive create an unversioned archive of a repository revision
499 archive create an unversioned archive of a repository revision
500 bundle create a bundle file
500 bundle create a bundle file
501 export dump the header and diffs for one or more changesets
501 export dump the header and diffs for one or more changesets
502 import import an ordered set of patches
502 import import an ordered set of patches
503 unbundle apply one or more bundle files
503 unbundle apply one or more bundle files
504
504
505 Repository maintenance:
505 Repository maintenance:
506
506
507 manifest output the current or given revision of the project manifest
507 manifest output the current or given revision of the project manifest
508 recover roll back an interrupted transaction
508 recover roll back an interrupted transaction
509 verify verify the integrity of the repository
509 verify verify the integrity of the repository
510
510
511 Help:
511 Help:
512
512
513 config show combined config settings from all hgrc files
513 config show combined config settings from all hgrc files
514 help show help for a given topic or a help overview
514 help show help for a given topic or a help overview
515 version output version and copyright information
515 version output version and copyright information
516
516
517 additional help topics:
517 additional help topics:
518
518
519 Mercurial identifiers:
519 Mercurial identifiers:
520
520
521 filesets Specifying File Sets
521 filesets Specifying File Sets
522 hgignore Syntax for Mercurial Ignore Files
522 hgignore Syntax for Mercurial Ignore Files
523 patterns File Name Patterns
523 patterns File Name Patterns
524 revisions Specifying Revisions
524 revisions Specifying Revisions
525 urls URL Paths
525 urls URL Paths
526
526
527 Mercurial output:
527 Mercurial output:
528
528
529 color Colorizing Outputs
529 color Colorizing Outputs
530 dates Date Formats
530 dates Date Formats
531 diffs Diff Formats
531 diffs Diff Formats
532 templating Template Usage
532 templating Template Usage
533
533
534 Mercurial configuration:
534 Mercurial configuration:
535
535
536 config Configuration Files
536 config Configuration Files
537 environment Environment Variables
537 environment Environment Variables
538 extensions Using Additional Features
538 extensions Using Additional Features
539 flags Command-line flags
539 flags Command-line flags
540 hgweb Configuring hgweb
540 hgweb Configuring hgweb
541 merge-tools Merge Tools
541 merge-tools Merge Tools
542 pager Pager Support
542 pager Pager Support
543
543
544 Concepts:
544 Concepts:
545
545
546 bundlespec Bundle File Formats
546 bundlespec Bundle File Formats
547 glossary Glossary
547 glossary Glossary
548 phases Working with Phases
548 phases Working with Phases
549 subrepos Subrepositories
549 subrepos Subrepositories
550
550
551 Miscellaneous:
551 Miscellaneous:
552
552
553 deprecated Deprecated Features
553 deprecated Deprecated Features
554 internals Technical implementation topics
554 internals Technical implementation topics
555 scripting Using Mercurial from scripts and automation
555 scripting Using Mercurial from scripts and automation
556
556
557 (use 'hg help -v' to show built-in aliases and global options)
557 (use 'hg help -v' to show built-in aliases and global options)
558
558
559 #endif
559 #endif
560
560
561 Not tested: --debugger
561 Not tested: --debugger
562
562
General Comments 0
You need to be logged in to leave comments. Login now