91 try: |
91 try: |
92 func(*args, **kwargs) |
92 func(*args, **kwargs) |
93 except: # re-raises below |
93 except: # re-raises below |
94 if exc is None: |
94 if exc is None: |
95 exc = sys.exc_info()[1] |
95 exc = sys.exc_info()[1] |
96 self.ui.warn('error in exit handlers:\n') |
96 self.ui.warn(b'error in exit handlers:\n') |
97 self.ui.traceback(force=True) |
97 self.ui.traceback(force=True) |
98 finally: |
98 finally: |
99 if exc is not None: |
99 if exc is not None: |
100 raise exc |
100 raise exc |
101 |
101 |
102 |
102 |
103 def run(): |
103 def run(): |
104 "run the command in sys.argv" |
104 b"run the command in sys.argv" |
105 initstdio() |
105 initstdio() |
106 with tracing.log('parse args into request'): |
106 with tracing.log(b'parse args into request'): |
107 req = request(pycompat.sysargv[1:]) |
107 req = request(pycompat.sysargv[1:]) |
108 err = None |
108 err = None |
109 try: |
109 try: |
110 status = dispatch(req) |
110 status = dispatch(req) |
111 except error.StdioError as e: |
111 except error.StdioError as e: |
112 err = e |
112 err = e |
113 status = -1 |
113 status = -1 |
114 |
114 |
115 # In all cases we try to flush stdio streams. |
115 # In all cases we try to flush stdio streams. |
116 if util.safehasattr(req.ui, 'fout'): |
116 if util.safehasattr(req.ui, b'fout'): |
117 try: |
117 try: |
118 req.ui.fout.flush() |
118 req.ui.fout.flush() |
119 except IOError as e: |
119 except IOError as e: |
120 err = e |
120 err = e |
121 status = -1 |
121 status = -1 |
122 |
122 |
123 if util.safehasattr(req.ui, 'ferr'): |
123 if util.safehasattr(req.ui, b'ferr'): |
124 try: |
124 try: |
125 if err is not None and err.errno != errno.EPIPE: |
125 if err is not None and err.errno != errno.EPIPE: |
126 req.ui.ferr.write( |
126 req.ui.ferr.write( |
127 'abort: %s\n' % encoding.strtolocal(err.strerror) |
127 b'abort: %s\n' % encoding.strtolocal(err.strerror) |
128 ) |
128 ) |
129 req.ui.ferr.flush() |
129 req.ui.ferr.flush() |
130 # There's not much we can do about an I/O error here. So (possibly) |
130 # There's not much we can do about an I/O error here. So (possibly) |
131 # change the status code and move on. |
131 # change the status code and move on. |
132 except IOError: |
132 except IOError: |
176 return [s for s in symbols if sim(s) > 0.6] |
176 return [s for s in symbols if sim(s) > 0.6] |
177 |
177 |
178 |
178 |
179 def _reportsimilar(write, similar): |
179 def _reportsimilar(write, similar): |
180 if len(similar) == 1: |
180 if len(similar) == 1: |
181 write(_("(did you mean %s?)\n") % similar[0]) |
181 write(_(b"(did you mean %s?)\n") % similar[0]) |
182 elif similar: |
182 elif similar: |
183 ss = ", ".join(sorted(similar)) |
183 ss = b", ".join(sorted(similar)) |
184 write(_("(did you mean one of %s?)\n") % ss) |
184 write(_(b"(did you mean one of %s?)\n") % ss) |
185 |
185 |
186 |
186 |
187 def _formatparse(write, inst): |
187 def _formatparse(write, inst): |
188 similar = [] |
188 similar = [] |
189 if isinstance(inst, error.UnknownIdentifier): |
189 if isinstance(inst, error.UnknownIdentifier): |
190 # make sure to check fileset first, as revset can invoke fileset |
190 # make sure to check fileset first, as revset can invoke fileset |
191 similar = _getsimilar(inst.symbols, inst.function) |
191 similar = _getsimilar(inst.symbols, inst.function) |
192 if len(inst.args) > 1: |
192 if len(inst.args) > 1: |
193 write( |
193 write( |
194 _("hg: parse error at %s: %s\n") |
194 _(b"hg: parse error at %s: %s\n") |
195 % (pycompat.bytestr(inst.args[1]), inst.args[0]) |
195 % (pycompat.bytestr(inst.args[1]), inst.args[0]) |
196 ) |
196 ) |
197 if inst.args[0].startswith(' '): |
197 if inst.args[0].startswith(b' '): |
198 write(_("unexpected leading whitespace\n")) |
198 write(_(b"unexpected leading whitespace\n")) |
199 else: |
199 else: |
200 write(_("hg: parse error: %s\n") % inst.args[0]) |
200 write(_(b"hg: parse error: %s\n") % inst.args[0]) |
201 _reportsimilar(write, similar) |
201 _reportsimilar(write, similar) |
202 if inst.hint: |
202 if inst.hint: |
203 write(_("(%s)\n") % inst.hint) |
203 write(_(b"(%s)\n") % inst.hint) |
204 |
204 |
205 |
205 |
206 def _formatargs(args): |
206 def _formatargs(args): |
207 return ' '.join(procutil.shellquote(a) for a in args) |
207 return b' '.join(procutil.shellquote(a) for a in args) |
208 |
208 |
209 |
209 |
210 def dispatch(req): |
210 def dispatch(req): |
211 """run the command specified in req.args; returns an integer status code""" |
211 """run the command specified in req.args; returns an integer status code""" |
212 with tracing.log('dispatch.dispatch'): |
212 with tracing.log(b'dispatch.dispatch'): |
213 if req.ferr: |
213 if req.ferr: |
214 ferr = req.ferr |
214 ferr = req.ferr |
215 elif req.ui: |
215 elif req.ui: |
216 ferr = req.ui.ferr |
216 ferr = req.ui.ferr |
217 else: |
217 else: |
246 starttime = util.timer() |
246 starttime = util.timer() |
247 ret = 1 # default of Python exit code on unhandled exception |
247 ret = 1 # default of Python exit code on unhandled exception |
248 try: |
248 try: |
249 ret = _runcatch(req) or 0 |
249 ret = _runcatch(req) or 0 |
250 except error.ProgrammingError as inst: |
250 except error.ProgrammingError as inst: |
251 req.ui.error(_('** ProgrammingError: %s\n') % inst) |
251 req.ui.error(_(b'** ProgrammingError: %s\n') % inst) |
252 if inst.hint: |
252 if inst.hint: |
253 req.ui.error(_('** (%s)\n') % inst.hint) |
253 req.ui.error(_(b'** (%s)\n') % inst.hint) |
254 raise |
254 raise |
255 except KeyboardInterrupt as inst: |
255 except KeyboardInterrupt as inst: |
256 try: |
256 try: |
257 if isinstance(inst, error.SignalInterrupt): |
257 if isinstance(inst, error.SignalInterrupt): |
258 msg = _("killed!\n") |
258 msg = _(b"killed!\n") |
259 else: |
259 else: |
260 msg = _("interrupted!\n") |
260 msg = _(b"interrupted!\n") |
261 req.ui.error(msg) |
261 req.ui.error(msg) |
262 except error.SignalInterrupt: |
262 except error.SignalInterrupt: |
263 # maybe pager would quit without consuming all the output, and |
263 # maybe pager would quit without consuming all the output, and |
264 # SIGPIPE was raised. we cannot print anything in this case. |
264 # SIGPIPE was raised. we cannot print anything in this case. |
265 pass |
265 pass |
328 # Don't handle this here. We know the command is |
328 # Don't handle this here. We know the command is |
329 # invalid, but all we're worried about for now is that |
329 # invalid, but all we're worried about for now is that |
330 # it's not a command that server operators expect to |
330 # it's not a command that server operators expect to |
331 # be safe to offer to users in a sandbox. |
331 # be safe to offer to users in a sandbox. |
332 pass |
332 pass |
333 if realcmd == 'serve' and '--stdio' in cmdargs: |
333 if realcmd == b'serve' and b'--stdio' in cmdargs: |
334 # We want to constrain 'hg serve --stdio' instances pretty |
334 # We want to constrain 'hg serve --stdio' instances pretty |
335 # closely, as many shared-ssh access tools want to grant |
335 # closely, as many shared-ssh access tools want to grant |
336 # access to run *only* 'hg -R $repo serve --stdio'. We |
336 # access to run *only* 'hg -R $repo serve --stdio'. We |
337 # restrict to exactly that set of arguments, and prohibit |
337 # restrict to exactly that set of arguments, and prohibit |
338 # any repo name that starts with '--' to prevent |
338 # any repo name that starts with '--' to prevent |
339 # shenanigans wherein a user does something like pass |
339 # shenanigans wherein a user does something like pass |
340 # --debugger or --config=ui.debugger=1 as a repo |
340 # --debugger or --config=ui.debugger=1 as a repo |
341 # name. This used to actually run the debugger. |
341 # name. This used to actually run the debugger. |
342 if ( |
342 if ( |
343 len(req.args) != 4 |
343 len(req.args) != 4 |
344 or req.args[0] != '-R' |
344 or req.args[0] != b'-R' |
345 or req.args[1].startswith('--') |
345 or req.args[1].startswith(b'--') |
346 or req.args[2] != 'serve' |
346 or req.args[2] != b'serve' |
347 or req.args[3] != '--stdio' |
347 or req.args[3] != b'--stdio' |
348 ): |
348 ): |
349 raise error.Abort( |
349 raise error.Abort( |
350 _('potentially unsafe serve --stdio invocation: %s') |
350 _(b'potentially unsafe serve --stdio invocation: %s') |
351 % (stringutil.pprint(req.args),) |
351 % (stringutil.pprint(req.args),) |
352 ) |
352 ) |
353 |
353 |
354 try: |
354 try: |
355 debugger = 'pdb' |
355 debugger = b'pdb' |
356 debugtrace = {'pdb': pdb.set_trace} |
356 debugtrace = {b'pdb': pdb.set_trace} |
357 debugmortem = {'pdb': pdb.post_mortem} |
357 debugmortem = {b'pdb': pdb.post_mortem} |
358 |
358 |
359 # read --config before doing anything else |
359 # read --config before doing anything else |
360 # (e.g. to change trust settings for reading .hg/hgrc) |
360 # (e.g. to change trust settings for reading .hg/hgrc) |
361 cfgs = _parseconfig(req.ui, req.earlyoptions['config']) |
361 cfgs = _parseconfig(req.ui, req.earlyoptions[b'config']) |
362 |
362 |
363 if req.repo: |
363 if req.repo: |
364 # copy configs that were passed on the cmdline (--config) to |
364 # copy configs that were passed on the cmdline (--config) to |
365 # the repo ui |
365 # the repo ui |
366 for sec, name, val in cfgs: |
366 for sec, name, val in cfgs: |
367 req.repo.ui.setconfig(sec, name, val, source='--config') |
367 req.repo.ui.setconfig( |
|
368 sec, name, val, source=b'--config' |
|
369 ) |
368 |
370 |
369 # developer config: ui.debugger |
371 # developer config: ui.debugger |
370 debugger = ui.config("ui", "debugger") |
372 debugger = ui.config(b"ui", b"debugger") |
371 debugmod = pdb |
373 debugmod = pdb |
372 if not debugger or ui.plain(): |
374 if not debugger or ui.plain(): |
373 # if we are in HGPLAIN mode, then disable custom debugging |
375 # if we are in HGPLAIN mode, then disable custom debugging |
374 debugger = 'pdb' |
376 debugger = b'pdb' |
375 elif req.earlyoptions['debugger']: |
377 elif req.earlyoptions[b'debugger']: |
376 # This import can be slow for fancy debuggers, so only |
378 # This import can be slow for fancy debuggers, so only |
377 # do it when absolutely necessary, i.e. when actual |
379 # do it when absolutely necessary, i.e. when actual |
378 # debugging has been requested |
380 # debugging has been requested |
379 with demandimport.deactivated(): |
381 with demandimport.deactivated(): |
380 try: |
382 try: |
384 |
386 |
385 debugtrace[debugger] = debugmod.set_trace |
387 debugtrace[debugger] = debugmod.set_trace |
386 debugmortem[debugger] = debugmod.post_mortem |
388 debugmortem[debugger] = debugmod.post_mortem |
387 |
389 |
388 # enter the debugger before command execution |
390 # enter the debugger before command execution |
389 if req.earlyoptions['debugger']: |
391 if req.earlyoptions[b'debugger']: |
390 ui.warn( |
392 ui.warn( |
391 _( |
393 _( |
392 "entering debugger - " |
394 b"entering debugger - " |
393 "type c to continue starting hg or h for help\n" |
395 b"type c to continue starting hg or h for help\n" |
394 ) |
396 ) |
395 ) |
397 ) |
396 |
398 |
397 if ( |
399 if ( |
398 debugger != 'pdb' |
400 debugger != b'pdb' |
399 and debugtrace[debugger] == debugtrace['pdb'] |
401 and debugtrace[debugger] == debugtrace[b'pdb'] |
400 ): |
402 ): |
401 ui.warn( |
403 ui.warn( |
402 _( |
404 _( |
403 "%s debugger specified " |
405 b"%s debugger specified " |
404 "but its module was not found\n" |
406 b"but its module was not found\n" |
405 ) |
407 ) |
406 % debugger |
408 % debugger |
407 ) |
409 ) |
408 with demandimport.deactivated(): |
410 with demandimport.deactivated(): |
409 debugtrace[debugger]() |
411 debugtrace[debugger]() |
428 """ |
430 """ |
429 try: |
431 try: |
430 return scmutil.callcatch(ui, func) |
432 return scmutil.callcatch(ui, func) |
431 except error.AmbiguousCommand as inst: |
433 except error.AmbiguousCommand as inst: |
432 ui.warn( |
434 ui.warn( |
433 _("hg: command '%s' is ambiguous:\n %s\n") |
435 _(b"hg: command '%s' is ambiguous:\n %s\n") |
434 % (inst.args[0], " ".join(inst.args[1])) |
436 % (inst.args[0], b" ".join(inst.args[1])) |
435 ) |
437 ) |
436 except error.CommandError as inst: |
438 except error.CommandError as inst: |
437 if inst.args[0]: |
439 if inst.args[0]: |
438 ui.pager('help') |
440 ui.pager(b'help') |
439 msgbytes = pycompat.bytestr(inst.args[1]) |
441 msgbytes = pycompat.bytestr(inst.args[1]) |
440 ui.warn(_("hg %s: %s\n") % (inst.args[0], msgbytes)) |
442 ui.warn(_(b"hg %s: %s\n") % (inst.args[0], msgbytes)) |
441 commands.help_(ui, inst.args[0], full=False, command=True) |
443 commands.help_(ui, inst.args[0], full=False, command=True) |
442 else: |
444 else: |
443 ui.warn(_("hg: %s\n") % inst.args[1]) |
445 ui.warn(_(b"hg: %s\n") % inst.args[1]) |
444 ui.warn(_("(use 'hg help -v' for a list of global options)\n")) |
446 ui.warn(_(b"(use 'hg help -v' for a list of global options)\n")) |
445 except error.ParseError as inst: |
447 except error.ParseError as inst: |
446 _formatparse(ui.warn, inst) |
448 _formatparse(ui.warn, inst) |
447 return -1 |
449 return -1 |
448 except error.UnknownCommand as inst: |
450 except error.UnknownCommand as inst: |
449 nocmdmsg = _("hg: unknown command '%s'\n") % inst.args[0] |
451 nocmdmsg = _(b"hg: unknown command '%s'\n") % inst.args[0] |
450 try: |
452 try: |
451 # check if the command is in a disabled extension |
453 # check if the command is in a disabled extension |
452 # (but don't check for extensions themselves) |
454 # (but don't check for extensions themselves) |
453 formatted = help.formattedhelp( |
455 formatted = help.formattedhelp( |
454 ui, commands, inst.args[0], unknowncmd=True |
456 ui, commands, inst.args[0], unknowncmd=True |
478 |
480 |
479 |
481 |
480 def aliasargs(fn, givenargs): |
482 def aliasargs(fn, givenargs): |
481 args = [] |
483 args = [] |
482 # only care about alias 'args', ignore 'args' set by extensions.wrapfunction |
484 # only care about alias 'args', ignore 'args' set by extensions.wrapfunction |
483 if not util.safehasattr(fn, '_origfunc'): |
485 if not util.safehasattr(fn, b'_origfunc'): |
484 args = getattr(fn, 'args', args) |
486 args = getattr(fn, 'args', args) |
485 if args: |
487 if args: |
486 cmd = ' '.join(map(procutil.shellquote, args)) |
488 cmd = b' '.join(map(procutil.shellquote, args)) |
487 |
489 |
488 nums = [] |
490 nums = [] |
489 |
491 |
490 def replacer(m): |
492 def replacer(m): |
491 num = int(m.group(1)) - 1 |
493 num = int(m.group(1)) - 1 |
492 nums.append(num) |
494 nums.append(num) |
493 if num < len(givenargs): |
495 if num < len(givenargs): |
494 return givenargs[num] |
496 return givenargs[num] |
495 raise error.Abort(_('too few arguments for command alias')) |
497 raise error.Abort(_(b'too few arguments for command alias')) |
496 |
498 |
497 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd) |
499 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd) |
498 givenargs = [x for i, x in enumerate(givenargs) if i not in nums] |
500 givenargs = [x for i, x in enumerate(givenargs) if i not in nums] |
499 args = pycompat.shlexsplit(cmd) |
501 args = pycompat.shlexsplit(cmd) |
500 return args + givenargs |
502 return args + givenargs |
505 |
507 |
506 This also handles $0, $@ and "$@". |
508 This also handles $0, $@ and "$@". |
507 ''' |
509 ''' |
508 # util.interpolate can't deal with "$@" (with quotes) because it's only |
510 # util.interpolate can't deal with "$@" (with quotes) because it's only |
509 # built to match prefix + patterns. |
511 # built to match prefix + patterns. |
510 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args)) |
512 replacemap = dict((b'$%d' % (i + 1), arg) for i, arg in enumerate(args)) |
511 replacemap['$0'] = name |
513 replacemap[b'$0'] = name |
512 replacemap['$$'] = '$' |
514 replacemap[b'$$'] = b'$' |
513 replacemap['$@'] = ' '.join(args) |
515 replacemap[b'$@'] = b' '.join(args) |
514 # Typical Unix shells interpolate "$@" (with quotes) as all the positional |
516 # Typical Unix shells interpolate "$@" (with quotes) as all the positional |
515 # parameters, separated out into words. Emulate the same behavior here by |
517 # parameters, separated out into words. Emulate the same behavior here by |
516 # quoting the arguments individually. POSIX shells will then typically |
518 # quoting the arguments individually. POSIX shells will then typically |
517 # tokenize each argument into exactly one word. |
519 # tokenize each argument into exactly one word. |
518 replacemap['"$@"'] = ' '.join(procutil.shellquote(arg) for arg in args) |
520 replacemap[b'"$@"'] = b' '.join(procutil.shellquote(arg) for arg in args) |
519 # escape '\$' for regex |
521 # escape '\$' for regex |
520 regex = '|'.join(replacemap.keys()).replace('$', br'\$') |
522 regex = b'|'.join(replacemap.keys()).replace(b'$', br'\$') |
521 r = re.compile(regex) |
523 r = re.compile(regex) |
522 return r.sub(lambda x: replacemap[x.group()], cmd) |
524 return r.sub(lambda x: replacemap[x.group()], cmd) |
523 |
525 |
524 |
526 |
525 class cmdalias(object): |
527 class cmdalias(object): |
526 def __init__(self, ui, name, definition, cmdtable, source): |
528 def __init__(self, ui, name, definition, cmdtable, source): |
527 self.name = self.cmd = name |
529 self.name = self.cmd = name |
528 self.cmdname = '' |
530 self.cmdname = b'' |
529 self.definition = definition |
531 self.definition = definition |
530 self.fn = None |
532 self.fn = None |
531 self.givenargs = [] |
533 self.givenargs = [] |
532 self.opts = [] |
534 self.opts = [] |
533 self.help = '' |
535 self.help = b'' |
534 self.badalias = None |
536 self.badalias = None |
535 self.unknowncmd = False |
537 self.unknowncmd = False |
536 self.source = source |
538 self.source = source |
537 |
539 |
538 try: |
540 try: |
544 self.shadows = True |
546 self.shadows = True |
545 except error.UnknownCommand: |
547 except error.UnknownCommand: |
546 self.shadows = False |
548 self.shadows = False |
547 |
549 |
548 if not self.definition: |
550 if not self.definition: |
549 self.badalias = _("no definition for alias '%s'") % self.name |
551 self.badalias = _(b"no definition for alias '%s'") % self.name |
550 return |
552 return |
551 |
553 |
552 if self.definition.startswith('!'): |
554 if self.definition.startswith(b'!'): |
553 shdef = self.definition[1:] |
555 shdef = self.definition[1:] |
554 self.shell = True |
556 self.shell = True |
555 |
557 |
556 def fn(ui, *args): |
558 def fn(ui, *args): |
557 env = {'HG_ARGS': ' '.join((self.name,) + args)} |
559 env = {b'HG_ARGS': b' '.join((self.name,) + args)} |
558 |
560 |
559 def _checkvar(m): |
561 def _checkvar(m): |
560 if m.groups()[0] == '$': |
562 if m.groups()[0] == b'$': |
561 return m.group() |
563 return m.group() |
562 elif int(m.groups()[0]) <= len(args): |
564 elif int(m.groups()[0]) <= len(args): |
563 return m.group() |
565 return m.group() |
564 else: |
566 else: |
565 ui.debug( |
567 ui.debug( |
566 "No argument found for substitution " |
568 b"No argument found for substitution " |
567 "of %i variable in alias '%s' definition.\n" |
569 b"of %i variable in alias '%s' definition.\n" |
568 % (int(m.groups()[0]), self.name) |
570 % (int(m.groups()[0]), self.name) |
569 ) |
571 ) |
570 return '' |
572 return b'' |
571 |
573 |
572 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef) |
574 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef) |
573 cmd = aliasinterpolate(self.name, args, cmd) |
575 cmd = aliasinterpolate(self.name, args, cmd) |
574 return ui.system( |
576 return ui.system( |
575 cmd, environ=env, blockedtag='alias_%s' % self.name |
577 cmd, environ=env, blockedtag=b'alias_%s' % self.name |
576 ) |
578 ) |
577 |
579 |
578 self.fn = fn |
580 self.fn = fn |
579 self.alias = True |
581 self.alias = True |
580 self._populatehelp(ui, name, shdef, self.fn) |
582 self._populatehelp(ui, name, shdef, self.fn) |
581 return |
583 return |
582 |
584 |
583 try: |
585 try: |
584 args = pycompat.shlexsplit(self.definition) |
586 args = pycompat.shlexsplit(self.definition) |
585 except ValueError as inst: |
587 except ValueError as inst: |
586 self.badalias = _("error in definition for alias '%s': %s") % ( |
588 self.badalias = _(b"error in definition for alias '%s': %s") % ( |
587 self.name, |
589 self.name, |
588 stringutil.forcebytestr(inst), |
590 stringutil.forcebytestr(inst), |
589 ) |
591 ) |
590 return |
592 return |
591 earlyopts, args = _earlysplitopts(args) |
593 earlyopts, args = _earlysplitopts(args) |
592 if earlyopts: |
594 if earlyopts: |
593 self.badalias = _( |
595 self.badalias = _( |
594 "error in definition for alias '%s': %s may " |
596 b"error in definition for alias '%s': %s may " |
595 "only be given on the command line" |
597 b"only be given on the command line" |
596 ) % (self.name, '/'.join(pycompat.ziplist(*earlyopts)[0])) |
598 ) % (self.name, b'/'.join(pycompat.ziplist(*earlyopts)[0])) |
597 return |
599 return |
598 self.cmdname = cmd = args.pop(0) |
600 self.cmdname = cmd = args.pop(0) |
599 self.givenargs = args |
601 self.givenargs = args |
600 |
602 |
601 try: |
603 try: |
608 |
610 |
609 self.alias = True |
611 self.alias = True |
610 self._populatehelp(ui, name, cmd, self.fn, cmdhelp) |
612 self._populatehelp(ui, name, cmd, self.fn, cmdhelp) |
611 |
613 |
612 except error.UnknownCommand: |
614 except error.UnknownCommand: |
613 self.badalias = _("alias '%s' resolves to unknown command '%s'") % ( |
615 self.badalias = _( |
614 self.name, |
616 b"alias '%s' resolves to unknown command '%s'" |
615 cmd, |
617 ) % (self.name, cmd,) |
616 ) |
|
617 self.unknowncmd = True |
618 self.unknowncmd = True |
618 except error.AmbiguousCommand: |
619 except error.AmbiguousCommand: |
619 self.badalias = _( |
620 self.badalias = _( |
620 "alias '%s' resolves to ambiguous command '%s'" |
621 b"alias '%s' resolves to ambiguous command '%s'" |
621 ) % (self.name, cmd) |
622 ) % (self.name, cmd) |
622 |
623 |
623 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None): |
624 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None): |
624 # confine strings to be passed to i18n.gettext() |
625 # confine strings to be passed to i18n.gettext() |
625 cfg = {} |
626 cfg = {} |
626 for k in ('doc', 'help', 'category'): |
627 for k in (b'doc', b'help', b'category'): |
627 v = ui.config('alias', '%s:%s' % (name, k), None) |
628 v = ui.config(b'alias', b'%s:%s' % (name, k), None) |
628 if v is None: |
629 if v is None: |
629 continue |
630 continue |
630 if not encoding.isasciistr(v): |
631 if not encoding.isasciistr(v): |
631 self.badalias = _( |
632 self.badalias = _( |
632 "non-ASCII character in alias definition " "'%s:%s'" |
633 b"non-ASCII character in alias definition " b"'%s:%s'" |
633 ) % (name, k) |
634 ) % (name, k) |
634 return |
635 return |
635 cfg[k] = v |
636 cfg[k] = v |
636 |
637 |
637 self.help = cfg.get('help', defaulthelp or '') |
638 self.help = cfg.get(b'help', defaulthelp or b'') |
638 if self.help and self.help.startswith("hg " + cmd): |
639 if self.help and self.help.startswith(b"hg " + cmd): |
639 # drop prefix in old-style help lines so hg shows the alias |
640 # drop prefix in old-style help lines so hg shows the alias |
640 self.help = self.help[4 + len(cmd) :] |
641 self.help = self.help[4 + len(cmd) :] |
641 |
642 |
642 self.owndoc = 'doc' in cfg |
643 self.owndoc = b'doc' in cfg |
643 doc = cfg.get('doc', pycompat.getdoc(fn)) |
644 doc = cfg.get(b'doc', pycompat.getdoc(fn)) |
644 if doc is not None: |
645 if doc is not None: |
645 doc = pycompat.sysstr(doc) |
646 doc = pycompat.sysstr(doc) |
646 self.__doc__ = doc |
647 self.__doc__ = doc |
647 |
648 |
648 self.helpcategory = cfg.get('category', registrar.command.CATEGORY_NONE) |
649 self.helpcategory = cfg.get( |
|
650 b'category', registrar.command.CATEGORY_NONE |
|
651 ) |
649 |
652 |
650 @property |
653 @property |
651 def args(self): |
654 def args(self): |
652 args = pycompat.maplist(util.expandpath, self.givenargs) |
655 args = pycompat.maplist(util.expandpath, self.givenargs) |
653 return aliasargs(self.fn, args) |
656 return aliasargs(self.fn, args) |
659 r'optionalrepo': False, |
662 r'optionalrepo': False, |
660 r'inferrepo': False, |
663 r'inferrepo': False, |
661 } |
664 } |
662 if name not in adefaults: |
665 if name not in adefaults: |
663 raise AttributeError(name) |
666 raise AttributeError(name) |
664 if self.badalias or util.safehasattr(self, 'shell'): |
667 if self.badalias or util.safehasattr(self, b'shell'): |
665 return adefaults[name] |
668 return adefaults[name] |
666 return getattr(self.fn, name) |
669 return getattr(self.fn, name) |
667 |
670 |
668 def __call__(self, ui, *args, **opts): |
671 def __call__(self, ui, *args, **opts): |
669 if self.badalias: |
672 if self.badalias: |
670 hint = None |
673 hint = None |
671 if self.unknowncmd: |
674 if self.unknowncmd: |
672 try: |
675 try: |
673 # check if the command is in a disabled extension |
676 # check if the command is in a disabled extension |
674 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2] |
677 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2] |
675 hint = _("'%s' is provided by '%s' extension") % (cmd, ext) |
678 hint = _(b"'%s' is provided by '%s' extension") % (cmd, ext) |
676 except error.UnknownCommand: |
679 except error.UnknownCommand: |
677 pass |
680 pass |
678 raise error.Abort(self.badalias, hint=hint) |
681 raise error.Abort(self.badalias, hint=hint) |
679 if self.shadows: |
682 if self.shadows: |
680 ui.debug( |
683 ui.debug( |
681 "alias '%s' shadows command '%s'\n" % (self.name, self.cmdname) |
684 b"alias '%s' shadows command '%s'\n" % (self.name, self.cmdname) |
682 ) |
685 ) |
683 |
686 |
684 ui.log( |
687 ui.log( |
685 'commandalias', |
688 b'commandalias', |
686 "alias '%s' expands to '%s'\n", |
689 b"alias '%s' expands to '%s'\n", |
687 self.name, |
690 self.name, |
688 self.definition, |
691 self.definition, |
689 ) |
692 ) |
690 if util.safehasattr(self, 'shell'): |
693 if util.safehasattr(self, b'shell'): |
691 return self.fn(ui, *args, **opts) |
694 return self.fn(ui, *args, **opts) |
692 else: |
695 else: |
693 try: |
696 try: |
694 return util.checksignature(self.fn)(ui, *args, **opts) |
697 return util.checksignature(self.fn)(ui, *args, **opts) |
695 except error.SignatureError: |
698 except error.SignatureError: |
696 args = ' '.join([self.cmdname] + self.args) |
699 args = b' '.join([self.cmdname] + self.args) |
697 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args)) |
700 ui.debug(b"alias '%s' expands to '%s'\n" % (self.name, args)) |
698 raise |
701 raise |
699 |
702 |
700 |
703 |
701 class lazyaliasentry(object): |
704 class lazyaliasentry(object): |
702 """like a typical command entry (func, opts, help), but is lazy""" |
705 """like a typical command entry (func, opts, help), but is lazy""" |
736 |
739 |
737 def addaliases(ui, cmdtable): |
740 def addaliases(ui, cmdtable): |
738 # aliases are processed after extensions have been loaded, so they |
741 # aliases are processed after extensions have been loaded, so they |
739 # may use extension commands. Aliases can also use other alias definitions, |
742 # may use extension commands. Aliases can also use other alias definitions, |
740 # but only if they have been defined prior to the current definition. |
743 # but only if they have been defined prior to the current definition. |
741 for alias, definition in ui.configitems('alias', ignoresub=True): |
744 for alias, definition in ui.configitems(b'alias', ignoresub=True): |
742 try: |
745 try: |
743 if cmdtable[alias].definition == definition: |
746 if cmdtable[alias].definition == definition: |
744 continue |
747 continue |
745 except (KeyError, AttributeError): |
748 except (KeyError, AttributeError): |
746 # definition might not exist or it might not be a cmdalias |
749 # definition might not exist or it might not be a cmdalias |
747 pass |
750 pass |
748 |
751 |
749 source = ui.configsource('alias', alias) |
752 source = ui.configsource(b'alias', alias) |
750 entry = lazyaliasentry(ui, alias, definition, cmdtable, source) |
753 entry = lazyaliasentry(ui, alias, definition, cmdtable, source) |
751 cmdtable[alias] = entry |
754 cmdtable[alias] = entry |
752 |
755 |
753 |
756 |
754 def _parse(ui, args): |
757 def _parse(ui, args): |
761 raise error.CommandError(None, stringutil.forcebytestr(inst)) |
764 raise error.CommandError(None, stringutil.forcebytestr(inst)) |
762 |
765 |
763 if args: |
766 if args: |
764 cmd, args = args[0], args[1:] |
767 cmd, args = args[0], args[1:] |
765 aliases, entry = cmdutil.findcmd( |
768 aliases, entry = cmdutil.findcmd( |
766 cmd, commands.table, ui.configbool("ui", "strict") |
769 cmd, commands.table, ui.configbool(b"ui", b"strict") |
767 ) |
770 ) |
768 cmd = aliases[0] |
771 cmd = aliases[0] |
769 args = aliasargs(entry[0], args) |
772 args = aliasargs(entry[0], args) |
770 defaults = ui.config("defaults", cmd) |
773 defaults = ui.config(b"defaults", cmd) |
771 if defaults: |
774 if defaults: |
772 args = ( |
775 args = ( |
773 pycompat.maplist(util.expandpath, pycompat.shlexsplit(defaults)) |
776 pycompat.maplist(util.expandpath, pycompat.shlexsplit(defaults)) |
774 + args |
777 + args |
775 ) |
778 ) |
800 """parse the --config options from the command line""" |
803 """parse the --config options from the command line""" |
801 configs = [] |
804 configs = [] |
802 |
805 |
803 for cfg in config: |
806 for cfg in config: |
804 try: |
807 try: |
805 name, value = [cfgelem.strip() for cfgelem in cfg.split('=', 1)] |
808 name, value = [cfgelem.strip() for cfgelem in cfg.split(b'=', 1)] |
806 section, name = name.split('.', 1) |
809 section, name = name.split(b'.', 1) |
807 if not section or not name: |
810 if not section or not name: |
808 raise IndexError |
811 raise IndexError |
809 ui.setconfig(section, name, value, '--config') |
812 ui.setconfig(section, name, value, b'--config') |
810 configs.append((section, name, value)) |
813 configs.append((section, name, value)) |
811 except (IndexError, ValueError): |
814 except (IndexError, ValueError): |
812 raise error.Abort( |
815 raise error.Abort( |
813 _( |
816 _( |
814 'malformed --config option: %r ' |
817 b'malformed --config option: %r ' |
815 '(use --config section.name=value)' |
818 b'(use --config section.name=value)' |
816 ) |
819 ) |
817 % pycompat.bytestr(cfg) |
820 % pycompat.bytestr(cfg) |
818 ) |
821 ) |
819 |
822 |
820 return configs |
823 return configs |
824 options = {} |
827 options = {} |
825 fancyopts.fancyopts( |
828 fancyopts.fancyopts( |
826 args, |
829 args, |
827 commands.globalopts, |
830 commands.globalopts, |
828 options, |
831 options, |
829 gnu=not ui.plain('strictflags'), |
832 gnu=not ui.plain(b'strictflags'), |
830 early=True, |
833 early=True, |
831 optaliases={'repository': ['repo']}, |
834 optaliases={b'repository': [b'repo']}, |
832 ) |
835 ) |
833 return options |
836 return options |
834 |
837 |
835 |
838 |
836 def _earlysplitopts(args): |
839 def _earlysplitopts(args): |
837 """Split args into a list of possible early options and remainder args""" |
840 """Split args into a list of possible early options and remainder args""" |
838 shortoptions = 'R:' |
841 shortoptions = b'R:' |
839 # TODO: perhaps 'debugger' should be included |
842 # TODO: perhaps 'debugger' should be included |
840 longoptions = ['cwd=', 'repository=', 'repo=', 'config='] |
843 longoptions = [b'cwd=', b'repository=', b'repo=', b'config='] |
841 return fancyopts.earlygetopt( |
844 return fancyopts.earlygetopt( |
842 args, shortoptions, longoptions, gnu=True, keepsep=True |
845 args, shortoptions, longoptions, gnu=True, keepsep=True |
843 ) |
846 ) |
844 |
847 |
845 |
848 |
846 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions): |
849 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions): |
847 # run pre-hook, and abort if it fails |
850 # run pre-hook, and abort if it fails |
848 hook.hook( |
851 hook.hook( |
849 lui, |
852 lui, |
850 repo, |
853 repo, |
851 "pre-%s" % cmd, |
854 b"pre-%s" % cmd, |
852 True, |
855 True, |
853 args=" ".join(fullargs), |
856 args=b" ".join(fullargs), |
854 pats=cmdpats, |
857 pats=cmdpats, |
855 opts=cmdoptions, |
858 opts=cmdoptions, |
856 ) |
859 ) |
857 try: |
860 try: |
858 ret = _runcommand(ui, options, cmd, d) |
861 ret = _runcommand(ui, options, cmd, d) |
859 # run post-hook, passing command result |
862 # run post-hook, passing command result |
860 hook.hook( |
863 hook.hook( |
861 lui, |
864 lui, |
862 repo, |
865 repo, |
863 "post-%s" % cmd, |
866 b"post-%s" % cmd, |
864 False, |
867 False, |
865 args=" ".join(fullargs), |
868 args=b" ".join(fullargs), |
866 result=ret, |
869 result=ret, |
867 pats=cmdpats, |
870 pats=cmdpats, |
868 opts=cmdoptions, |
871 opts=cmdoptions, |
869 ) |
872 ) |
870 except Exception: |
873 except Exception: |
871 # run failure hook and re-raise |
874 # run failure hook and re-raise |
872 hook.hook( |
875 hook.hook( |
873 lui, |
876 lui, |
874 repo, |
877 repo, |
875 "fail-%s" % cmd, |
878 b"fail-%s" % cmd, |
876 False, |
879 False, |
877 args=" ".join(fullargs), |
880 args=b" ".join(fullargs), |
878 pats=cmdpats, |
881 pats=cmdpats, |
879 opts=cmdoptions, |
882 opts=cmdoptions, |
880 ) |
883 ) |
881 raise |
884 raise |
882 return ret |
885 return ret |
890 if wd is None: |
893 if wd is None: |
891 try: |
894 try: |
892 wd = encoding.getcwd() |
895 wd = encoding.getcwd() |
893 except OSError as e: |
896 except OSError as e: |
894 raise error.Abort( |
897 raise error.Abort( |
895 _("error getting current working directory: %s") |
898 _(b"error getting current working directory: %s") |
896 % encoding.strtolocal(e.strerror) |
899 % encoding.strtolocal(e.strerror) |
897 ) |
900 ) |
898 path = cmdutil.findrepo(wd) or "" |
901 path = cmdutil.findrepo(wd) or b"" |
899 if not path: |
902 if not path: |
900 lui = ui |
903 lui = ui |
901 else: |
904 else: |
902 lui = ui.copy() |
905 lui = ui.copy() |
903 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path) |
906 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path) |
904 |
907 |
905 if rpath: |
908 if rpath: |
906 path = lui.expandpath(rpath) |
909 path = lui.expandpath(rpath) |
907 lui = ui.copy() |
910 lui = ui.copy() |
908 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path) |
911 lui.readconfig(os.path.join(path, b".hg", b"hgrc"), path) |
909 |
912 |
910 return path, lui |
913 return path, lui |
911 |
914 |
912 |
915 |
913 def _checkshellalias(lui, ui, args): |
916 def _checkshellalias(lui, ui, args): |
924 |
927 |
925 cmdtable = commands.table |
928 cmdtable = commands.table |
926 |
929 |
927 cmd = args[0] |
930 cmd = args[0] |
928 try: |
931 try: |
929 strict = ui.configbool("ui", "strict") |
932 strict = ui.configbool(b"ui", b"strict") |
930 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict) |
933 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict) |
931 except (error.AmbiguousCommand, error.UnknownCommand): |
934 except (error.AmbiguousCommand, error.UnknownCommand): |
932 return |
935 return |
933 |
936 |
934 cmd = aliases[0] |
937 cmd = aliases[0] |
935 fn = entry[0] |
938 fn = entry[0] |
936 |
939 |
937 if cmd and util.safehasattr(fn, 'shell'): |
940 if cmd and util.safehasattr(fn, b'shell'): |
938 # shell alias shouldn't receive early options which are consumed by hg |
941 # shell alias shouldn't receive early options which are consumed by hg |
939 _earlyopts, args = _earlysplitopts(args) |
942 _earlyopts, args = _earlysplitopts(args) |
940 d = lambda: fn(ui, *args[1:]) |
943 d = lambda: fn(ui, *args[1:]) |
941 return lambda: runcommand( |
944 return lambda: runcommand( |
942 lui, None, cmd, args[:1], ui, options, d, [], {} |
945 lui, None, cmd, args[:1], ui, options, d, [], {} |
946 def _dispatch(req): |
949 def _dispatch(req): |
947 args = req.args |
950 args = req.args |
948 ui = req.ui |
951 ui = req.ui |
949 |
952 |
950 # check for cwd |
953 # check for cwd |
951 cwd = req.earlyoptions['cwd'] |
954 cwd = req.earlyoptions[b'cwd'] |
952 if cwd: |
955 if cwd: |
953 os.chdir(cwd) |
956 os.chdir(cwd) |
954 |
957 |
955 rpath = req.earlyoptions['repository'] |
958 rpath = req.earlyoptions[b'repository'] |
956 path, lui = _getlocal(ui, rpath) |
959 path, lui = _getlocal(ui, rpath) |
957 |
960 |
958 uis = {ui, lui} |
961 uis = {ui, lui} |
959 |
962 |
960 if req.repo: |
963 if req.repo: |
961 uis.add(req.repo.ui) |
964 uis.add(req.repo.ui) |
962 |
965 |
963 if ( |
966 if ( |
964 req.earlyoptions['verbose'] |
967 req.earlyoptions[b'verbose'] |
965 or req.earlyoptions['debug'] |
968 or req.earlyoptions[b'debug'] |
966 or req.earlyoptions['quiet'] |
969 or req.earlyoptions[b'quiet'] |
967 ): |
970 ): |
968 for opt in ('verbose', 'debug', 'quiet'): |
971 for opt in (b'verbose', b'debug', b'quiet'): |
969 val = pycompat.bytestr(bool(req.earlyoptions[opt])) |
972 val = pycompat.bytestr(bool(req.earlyoptions[opt])) |
970 for ui_ in uis: |
973 for ui_ in uis: |
971 ui_.setconfig('ui', opt, val, '--' + opt) |
974 ui_.setconfig(b'ui', opt, val, b'--' + opt) |
972 |
975 |
973 if req.earlyoptions['profile']: |
976 if req.earlyoptions[b'profile']: |
974 for ui_ in uis: |
977 for ui_ in uis: |
975 ui_.setconfig('profiling', 'enabled', 'true', '--profile') |
978 ui_.setconfig(b'profiling', b'enabled', b'true', b'--profile') |
976 |
979 |
977 profile = lui.configbool('profiling', 'enabled') |
980 profile = lui.configbool(b'profiling', b'enabled') |
978 with profiling.profile(lui, enabled=profile) as profiler: |
981 with profiling.profile(lui, enabled=profile) as profiler: |
979 # Configure extensions in phases: uisetup, extsetup, cmdtable, and |
982 # Configure extensions in phases: uisetup, extsetup, cmdtable, and |
980 # reposetup |
983 # reposetup |
981 extensions.loadall(lui) |
984 extensions.loadall(lui) |
982 # Propagate any changes to lui.__class__ by extensions |
985 # Propagate any changes to lui.__class__ by extensions |
996 for ui_ in uis: |
999 for ui_ in uis: |
997 extensions.populateui(ui_) |
1000 extensions.populateui(ui_) |
998 return shellaliasfn() |
1001 return shellaliasfn() |
999 |
1002 |
1000 # check for fallback encoding |
1003 # check for fallback encoding |
1001 fallback = lui.config('ui', 'fallbackencoding') |
1004 fallback = lui.config(b'ui', b'fallbackencoding') |
1002 if fallback: |
1005 if fallback: |
1003 encoding.fallbackencoding = fallback |
1006 encoding.fallbackencoding = fallback |
1004 |
1007 |
1005 fullargs = args |
1008 fullargs = args |
1006 cmd, func, args, options, cmdoptions = _parse(lui, args) |
1009 cmd, func, args, options, cmdoptions = _parse(lui, args) |
1007 |
1010 |
1008 # store the canonical command name in request object for later access |
1011 # store the canonical command name in request object for later access |
1009 req.canonical_command = cmd |
1012 req.canonical_command = cmd |
1010 |
1013 |
1011 if options["config"] != req.earlyoptions["config"]: |
1014 if options[b"config"] != req.earlyoptions[b"config"]: |
1012 raise error.Abort(_("option --config may not be abbreviated!")) |
1015 raise error.Abort(_(b"option --config may not be abbreviated!")) |
1013 if options["cwd"] != req.earlyoptions["cwd"]: |
1016 if options[b"cwd"] != req.earlyoptions[b"cwd"]: |
1014 raise error.Abort(_("option --cwd may not be abbreviated!")) |
1017 raise error.Abort(_(b"option --cwd may not be abbreviated!")) |
1015 if options["repository"] != req.earlyoptions["repository"]: |
1018 if options[b"repository"] != req.earlyoptions[b"repository"]: |
1016 raise error.Abort( |
1019 raise error.Abort( |
1017 _( |
1020 _( |
1018 "option -R has to be separated from other options (e.g. not " |
1021 b"option -R has to be separated from other options (e.g. not " |
1019 "-qR) and --repository may only be abbreviated as --repo!" |
1022 b"-qR) and --repository may only be abbreviated as --repo!" |
1020 ) |
1023 ) |
1021 ) |
1024 ) |
1022 if options["debugger"] != req.earlyoptions["debugger"]: |
1025 if options[b"debugger"] != req.earlyoptions[b"debugger"]: |
1023 raise error.Abort(_("option --debugger may not be abbreviated!")) |
1026 raise error.Abort(_(b"option --debugger may not be abbreviated!")) |
1024 # don't validate --profile/--traceback, which can be enabled from now |
1027 # don't validate --profile/--traceback, which can be enabled from now |
1025 |
1028 |
1026 if options["encoding"]: |
1029 if options[b"encoding"]: |
1027 encoding.encoding = options["encoding"] |
1030 encoding.encoding = options[b"encoding"] |
1028 if options["encodingmode"]: |
1031 if options[b"encodingmode"]: |
1029 encoding.encodingmode = options["encodingmode"] |
1032 encoding.encodingmode = options[b"encodingmode"] |
1030 if options["time"]: |
1033 if options[b"time"]: |
1031 |
1034 |
1032 def get_times(): |
1035 def get_times(): |
1033 t = os.times() |
1036 t = os.times() |
1034 if t[4] == 0.0: |
1037 if t[4] == 0.0: |
1035 # Windows leaves this as zero, so use time.clock() |
1038 # Windows leaves this as zero, so use time.clock() |
1039 s = get_times() |
1042 s = get_times() |
1040 |
1043 |
1041 def print_time(): |
1044 def print_time(): |
1042 t = get_times() |
1045 t = get_times() |
1043 ui.warn( |
1046 ui.warn( |
1044 _("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") |
1047 _(b"time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") |
1045 % ( |
1048 % ( |
1046 t[4] - s[4], |
1049 t[4] - s[4], |
1047 t[0] - s[0], |
1050 t[0] - s[0], |
1048 t[2] - s[2], |
1051 t[2] - s[2], |
1049 t[1] - s[1], |
1052 t[1] - s[1], |
1050 t[3] - s[3], |
1053 t[3] - s[3], |
1051 ) |
1054 ) |
1052 ) |
1055 ) |
1053 |
1056 |
1054 ui.atexit(print_time) |
1057 ui.atexit(print_time) |
1055 if options["profile"]: |
1058 if options[b"profile"]: |
1056 profiler.start() |
1059 profiler.start() |
1057 |
1060 |
1058 # if abbreviated version of this were used, take them in account, now |
1061 # if abbreviated version of this were used, take them in account, now |
1059 if options['verbose'] or options['debug'] or options['quiet']: |
1062 if options[b'verbose'] or options[b'debug'] or options[b'quiet']: |
1060 for opt in ('verbose', 'debug', 'quiet'): |
1063 for opt in (b'verbose', b'debug', b'quiet'): |
1061 if options[opt] == req.earlyoptions[opt]: |
1064 if options[opt] == req.earlyoptions[opt]: |
1062 continue |
1065 continue |
1063 val = pycompat.bytestr(bool(options[opt])) |
1066 val = pycompat.bytestr(bool(options[opt])) |
1064 for ui_ in uis: |
1067 for ui_ in uis: |
1065 ui_.setconfig('ui', opt, val, '--' + opt) |
1068 ui_.setconfig(b'ui', opt, val, b'--' + opt) |
1066 |
1069 |
1067 if options['traceback']: |
1070 if options[b'traceback']: |
1068 for ui_ in uis: |
1071 for ui_ in uis: |
1069 ui_.setconfig('ui', 'traceback', 'on', '--traceback') |
1072 ui_.setconfig(b'ui', b'traceback', b'on', b'--traceback') |
1070 |
1073 |
1071 if options['noninteractive']: |
1074 if options[b'noninteractive']: |
1072 for ui_ in uis: |
1075 for ui_ in uis: |
1073 ui_.setconfig('ui', 'interactive', 'off', '-y') |
1076 ui_.setconfig(b'ui', b'interactive', b'off', b'-y') |
1074 |
1077 |
1075 if cmdoptions.get('insecure', False): |
1078 if cmdoptions.get(b'insecure', False): |
1076 for ui_ in uis: |
1079 for ui_ in uis: |
1077 ui_.insecureconnections = True |
1080 ui_.insecureconnections = True |
1078 |
1081 |
1079 # setup color handling before pager, because setting up pager |
1082 # setup color handling before pager, because setting up pager |
1080 # might cause incorrect console information |
1083 # might cause incorrect console information |
1081 coloropt = options['color'] |
1084 coloropt = options[b'color'] |
1082 for ui_ in uis: |
1085 for ui_ in uis: |
1083 if coloropt: |
1086 if coloropt: |
1084 ui_.setconfig('ui', 'color', coloropt, '--color') |
1087 ui_.setconfig(b'ui', b'color', coloropt, b'--color') |
1085 color.setup(ui_) |
1088 color.setup(ui_) |
1086 |
1089 |
1087 if stringutil.parsebool(options['pager']): |
1090 if stringutil.parsebool(options[b'pager']): |
1088 # ui.pager() expects 'internal-always-' prefix in this case |
1091 # ui.pager() expects 'internal-always-' prefix in this case |
1089 ui.pager('internal-always-' + cmd) |
1092 ui.pager(b'internal-always-' + cmd) |
1090 elif options['pager'] != 'auto': |
1093 elif options[b'pager'] != b'auto': |
1091 for ui_ in uis: |
1094 for ui_ in uis: |
1092 ui_.disablepager() |
1095 ui_.disablepager() |
1093 |
1096 |
1094 # configs are fully loaded, set up the ui instances |
1097 # configs are fully loaded, set up the ui instances |
1095 for ui_ in uis: |
1098 for ui_ in uis: |
1096 extensions.populateui(ui_) |
1099 extensions.populateui(ui_) |
1097 |
1100 |
1098 if options['version']: |
1101 if options[b'version']: |
1099 return commands.version_(ui) |
1102 return commands.version_(ui) |
1100 if options['help']: |
1103 if options[b'help']: |
1101 return commands.help_(ui, cmd, command=cmd is not None) |
1104 return commands.help_(ui, cmd, command=cmd is not None) |
1102 elif not cmd: |
1105 elif not cmd: |
1103 return commands.help_(ui, 'shortlist') |
1106 return commands.help_(ui, b'shortlist') |
1104 |
1107 |
1105 repo = None |
1108 repo = None |
1106 cmdpats = args[:] |
1109 cmdpats = args[:] |
1107 if not func.norepo: |
1110 if not func.norepo: |
1108 # use the repo from the request only if we don't have -R |
1111 # use the repo from the request only if we don't have -R |
1123 presetupfuncs=req.prereposetups, |
1126 presetupfuncs=req.prereposetups, |
1124 intents=func.intents, |
1127 intents=func.intents, |
1125 ) |
1128 ) |
1126 if not repo.local(): |
1129 if not repo.local(): |
1127 raise error.Abort( |
1130 raise error.Abort( |
1128 _("repository '%s' is not local") % path |
1131 _(b"repository '%s' is not local") % path |
1129 ) |
1132 ) |
1130 repo.ui.setconfig( |
1133 repo.ui.setconfig( |
1131 "bundle", "mainreporoot", repo.root, 'repo' |
1134 b"bundle", b"mainreporoot", repo.root, b'repo' |
1132 ) |
1135 ) |
1133 except error.RequirementError: |
1136 except error.RequirementError: |
1134 raise |
1137 raise |
1135 except error.RepoError: |
1138 except error.RepoError: |
1136 if rpath: # invalid -R path |
1139 if rpath: # invalid -R path |
1139 if func.inferrepo and args and not path: |
1142 if func.inferrepo and args and not path: |
1140 # try to infer -R from command args |
1143 # try to infer -R from command args |
1141 repos = pycompat.maplist(cmdutil.findrepo, args) |
1144 repos = pycompat.maplist(cmdutil.findrepo, args) |
1142 guess = repos[0] |
1145 guess = repos[0] |
1143 if guess and repos.count(guess) == len(repos): |
1146 if guess and repos.count(guess) == len(repos): |
1144 req.args = ['--repository', guess] + fullargs |
1147 req.args = [b'--repository', guess] + fullargs |
1145 req.earlyoptions['repository'] = guess |
1148 req.earlyoptions[b'repository'] = guess |
1146 return _dispatch(req) |
1149 return _dispatch(req) |
1147 if not path: |
1150 if not path: |
1148 raise error.RepoError( |
1151 raise error.RepoError( |
1149 _( |
1152 _( |
1150 "no repository found in" |
1153 b"no repository found in" |
1151 " '%s' (.hg not found)" |
1154 b" '%s' (.hg not found)" |
1152 ) |
1155 ) |
1153 % encoding.getcwd() |
1156 % encoding.getcwd() |
1154 ) |
1157 ) |
1155 raise |
1158 raise |
1156 if repo: |
1159 if repo: |
1157 ui = repo.ui |
1160 ui = repo.ui |
1158 if options['hidden']: |
1161 if options[b'hidden']: |
1159 repo = repo.unfiltered() |
1162 repo = repo.unfiltered() |
1160 args.insert(0, repo) |
1163 args.insert(0, repo) |
1161 elif rpath: |
1164 elif rpath: |
1162 ui.warn(_("warning: --repository ignored\n")) |
1165 ui.warn(_(b"warning: --repository ignored\n")) |
1163 |
1166 |
1164 msg = _formatargs(fullargs) |
1167 msg = _formatargs(fullargs) |
1165 ui.log("command", '%s\n', msg) |
1168 ui.log(b"command", b'%s\n', msg) |
1166 strcmdopt = pycompat.strkwargs(cmdoptions) |
1169 strcmdopt = pycompat.strkwargs(cmdoptions) |
1167 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt) |
1170 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt) |
1168 try: |
1171 try: |
1169 return runcommand( |
1172 return runcommand( |
1170 lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions |
1173 lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions |
1175 |
1178 |
1176 |
1179 |
1177 def _runcommand(ui, options, cmd, cmdfunc): |
1180 def _runcommand(ui, options, cmd, cmdfunc): |
1178 """Run a command function, possibly with profiling enabled.""" |
1181 """Run a command function, possibly with profiling enabled.""" |
1179 try: |
1182 try: |
1180 with tracing.log("Running %s command" % cmd): |
1183 with tracing.log(b"Running %s command" % cmd): |
1181 return cmdfunc() |
1184 return cmdfunc() |
1182 except error.SignatureError: |
1185 except error.SignatureError: |
1183 raise error.CommandError(cmd, _('invalid arguments')) |
1186 raise error.CommandError(cmd, _(b'invalid arguments')) |
1184 |
1187 |
1185 |
1188 |
1186 def _exceptionwarning(ui): |
1189 def _exceptionwarning(ui): |
1187 """Produce a warning message for the current active exception""" |
1190 """Produce a warning message for the current active exception""" |
1188 |
1191 |
1192 # probably built from fairly close to a tag and anyone with a |
1195 # probably built from fairly close to a tag and anyone with a |
1193 # 'make local' copy of hg (where the version number can be out |
1196 # 'make local' copy of hg (where the version number can be out |
1194 # of date) will be clueful enough to notice the implausible |
1197 # of date) will be clueful enough to notice the implausible |
1195 # version number and try updating. |
1198 # version number and try updating. |
1196 ct = util.versiontuple(n=2) |
1199 ct = util.versiontuple(n=2) |
1197 worst = None, ct, '' |
1200 worst = None, ct, b'' |
1198 if ui.config('ui', 'supportcontact') is None: |
1201 if ui.config(b'ui', b'supportcontact') is None: |
1199 for name, mod in extensions.extensions(): |
1202 for name, mod in extensions.extensions(): |
1200 # 'testedwith' should be bytes, but not all extensions are ported |
1203 # 'testedwith' should be bytes, but not all extensions are ported |
1201 # to py3 and we don't want UnicodeException because of that. |
1204 # to py3 and we don't want UnicodeException because of that. |
1202 testedwith = stringutil.forcebytestr(getattr(mod, 'testedwith', '')) |
1205 testedwith = stringutil.forcebytestr( |
1203 report = getattr(mod, 'buglink', _('the extension author.')) |
1206 getattr(mod, 'testedwith', b'') |
|
1207 ) |
|
1208 report = getattr(mod, 'buglink', _(b'the extension author.')) |
1204 if not testedwith.strip(): |
1209 if not testedwith.strip(): |
1205 # We found an untested extension. It's likely the culprit. |
1210 # We found an untested extension. It's likely the culprit. |
1206 worst = name, 'unknown', report |
1211 worst = name, b'unknown', report |
1207 break |
1212 break |
1208 |
1213 |
1209 # Never blame on extensions bundled with Mercurial. |
1214 # Never blame on extensions bundled with Mercurial. |
1210 if extensions.ismoduleinternal(mod): |
1215 if extensions.ismoduleinternal(mod): |
1211 continue |
1216 continue |
1219 if worst[0] is None or nearest < worst[1]: |
1224 if worst[0] is None or nearest < worst[1]: |
1220 worst = name, nearest, report |
1225 worst = name, nearest, report |
1221 if worst[0] is not None: |
1226 if worst[0] is not None: |
1222 name, testedwith, report = worst |
1227 name, testedwith, report = worst |
1223 if not isinstance(testedwith, (bytes, str)): |
1228 if not isinstance(testedwith, (bytes, str)): |
1224 testedwith = '.'.join( |
1229 testedwith = b'.'.join( |
1225 [stringutil.forcebytestr(c) for c in testedwith] |
1230 [stringutil.forcebytestr(c) for c in testedwith] |
1226 ) |
1231 ) |
1227 warning = _( |
1232 warning = _( |
1228 '** Unknown exception encountered with ' |
1233 b'** Unknown exception encountered with ' |
1229 'possibly-broken third-party extension %s\n' |
1234 b'possibly-broken third-party extension %s\n' |
1230 '** which supports versions %s of Mercurial.\n' |
1235 b'** which supports versions %s of Mercurial.\n' |
1231 '** Please disable %s and try your action again.\n' |
1236 b'** Please disable %s and try your action again.\n' |
1232 '** If that fixes the bug please report it to %s\n' |
1237 b'** If that fixes the bug please report it to %s\n' |
1233 ) % (name, testedwith, name, stringutil.forcebytestr(report)) |
1238 ) % (name, testedwith, name, stringutil.forcebytestr(report)) |
1234 else: |
1239 else: |
1235 bugtracker = ui.config('ui', 'supportcontact') |
1240 bugtracker = ui.config(b'ui', b'supportcontact') |
1236 if bugtracker is None: |
1241 if bugtracker is None: |
1237 bugtracker = _("https://mercurial-scm.org/wiki/BugTracker") |
1242 bugtracker = _(b"https://mercurial-scm.org/wiki/BugTracker") |
1238 warning = ( |
1243 warning = ( |
1239 _( |
1244 _( |
1240 "** unknown exception encountered, " |
1245 b"** unknown exception encountered, " |
1241 "please report by visiting\n** " |
1246 b"please report by visiting\n** " |
1242 ) |
1247 ) |
1243 + bugtracker |
1248 + bugtracker |
1244 + '\n' |
1249 + b'\n' |
1245 ) |
1250 ) |
1246 sysversion = pycompat.sysbytes(sys.version).replace('\n', '') |
1251 sysversion = pycompat.sysbytes(sys.version).replace(b'\n', b'') |
1247 warning += ( |
1252 warning += ( |
1248 (_("** Python %s\n") % sysversion) |
1253 (_(b"** Python %s\n") % sysversion) |
1249 + (_("** Mercurial Distributed SCM (version %s)\n") % util.version()) |
1254 + (_(b"** Mercurial Distributed SCM (version %s)\n") % util.version()) |
1250 + ( |
1255 + ( |
1251 _("** Extensions loaded: %s\n") |
1256 _(b"** Extensions loaded: %s\n") |
1252 % ", ".join([x[0] for x in extensions.extensions()]) |
1257 % b", ".join([x[0] for x in extensions.extensions()]) |
1253 ) |
1258 ) |
1254 ) |
1259 ) |
1255 return warning |
1260 return warning |
1256 |
1261 |
1257 |
1262 |