Mercurial > hg
comparison mercurial/dispatch.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | dd97354b8891 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
46 from .utils import ( | 46 from .utils import ( |
47 procutil, | 47 procutil, |
48 stringutil, | 48 stringutil, |
49 ) | 49 ) |
50 | 50 |
51 | |
51 class request(object): | 52 class request(object): |
52 def __init__(self, args, ui=None, repo=None, fin=None, fout=None, | 53 def __init__( |
53 ferr=None, fmsg=None, prereposetups=None): | 54 self, |
55 args, | |
56 ui=None, | |
57 repo=None, | |
58 fin=None, | |
59 fout=None, | |
60 ferr=None, | |
61 fmsg=None, | |
62 prereposetups=None, | |
63 ): | |
54 self.args = args | 64 self.args = args |
55 self.ui = ui | 65 self.ui = ui |
56 self.repo = repo | 66 self.repo = repo |
57 | 67 |
58 # input/output/error streams | 68 # input/output/error streams |
78 try: | 88 try: |
79 while handlers: | 89 while handlers: |
80 func, args, kwargs = handlers.pop() | 90 func, args, kwargs = handlers.pop() |
81 try: | 91 try: |
82 func(*args, **kwargs) | 92 func(*args, **kwargs) |
83 except: # re-raises below | 93 except: # re-raises below |
84 if exc is None: | 94 if exc is None: |
85 exc = sys.exc_info()[1] | 95 exc = sys.exc_info()[1] |
86 self.ui.warn(('error in exit handlers:\n')) | 96 self.ui.warn('error in exit handlers:\n') |
87 self.ui.traceback(force=True) | 97 self.ui.traceback(force=True) |
88 finally: | 98 finally: |
89 if exc is not None: | 99 if exc is not None: |
90 raise exc | 100 raise exc |
101 | |
91 | 102 |
92 def run(): | 103 def run(): |
93 "run the command in sys.argv" | 104 "run the command in sys.argv" |
94 initstdio() | 105 initstdio() |
95 with tracing.log('parse args into request'): | 106 with tracing.log('parse args into request'): |
110 status = -1 | 121 status = -1 |
111 | 122 |
112 if util.safehasattr(req.ui, 'ferr'): | 123 if util.safehasattr(req.ui, 'ferr'): |
113 try: | 124 try: |
114 if err is not None and err.errno != errno.EPIPE: | 125 if err is not None and err.errno != errno.EPIPE: |
115 req.ui.ferr.write('abort: %s\n' % | 126 req.ui.ferr.write( |
116 encoding.strtolocal(err.strerror)) | 127 'abort: %s\n' % encoding.strtolocal(err.strerror) |
128 ) | |
117 req.ui.ferr.flush() | 129 req.ui.ferr.flush() |
118 # 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) |
119 # change the status code and move on. | 131 # change the status code and move on. |
120 except IOError: | 132 except IOError: |
121 status = -1 | 133 status = -1 |
122 | 134 |
123 _silencestdio() | 135 _silencestdio() |
124 sys.exit(status & 255) | 136 sys.exit(status & 255) |
125 | 137 |
138 | |
126 if pycompat.ispy3: | 139 if pycompat.ispy3: |
140 | |
127 def initstdio(): | 141 def initstdio(): |
128 pass | 142 pass |
129 | 143 |
130 def _silencestdio(): | 144 def _silencestdio(): |
131 for fp in (sys.stdout, sys.stderr): | 145 for fp in (sys.stdout, sys.stderr): |
141 # and its close() actually closes the underlying file descriptor. | 155 # and its close() actually closes the underlying file descriptor. |
142 try: | 156 try: |
143 fp.close() | 157 fp.close() |
144 except IOError: | 158 except IOError: |
145 pass | 159 pass |
160 | |
161 | |
146 else: | 162 else: |
163 | |
147 def initstdio(): | 164 def initstdio(): |
148 for fp in (sys.stdin, sys.stdout, sys.stderr): | 165 for fp in (sys.stdin, sys.stdout, sys.stderr): |
149 procutil.setbinary(fp) | 166 procutil.setbinary(fp) |
150 | 167 |
151 def _silencestdio(): | 168 def _silencestdio(): |
152 pass | 169 pass |
170 | |
153 | 171 |
154 def _getsimilar(symbols, value): | 172 def _getsimilar(symbols, value): |
155 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio() | 173 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio() |
156 # The cutoff for similarity here is pretty arbitrary. It should | 174 # The cutoff for similarity here is pretty arbitrary. It should |
157 # probably be investigated and tweaked. | 175 # probably be investigated and tweaked. |
158 return [s for s in symbols if sim(s) > 0.6] | 176 return [s for s in symbols if sim(s) > 0.6] |
177 | |
159 | 178 |
160 def _reportsimilar(write, similar): | 179 def _reportsimilar(write, similar): |
161 if len(similar) == 1: | 180 if len(similar) == 1: |
162 write(_("(did you mean %s?)\n") % similar[0]) | 181 write(_("(did you mean %s?)\n") % similar[0]) |
163 elif similar: | 182 elif similar: |
164 ss = ", ".join(sorted(similar)) | 183 ss = ", ".join(sorted(similar)) |
165 write(_("(did you mean one of %s?)\n") % ss) | 184 write(_("(did you mean one of %s?)\n") % ss) |
166 | 185 |
186 | |
167 def _formatparse(write, inst): | 187 def _formatparse(write, inst): |
168 similar = [] | 188 similar = [] |
169 if isinstance(inst, error.UnknownIdentifier): | 189 if isinstance(inst, error.UnknownIdentifier): |
170 # make sure to check fileset first, as revset can invoke fileset | 190 # make sure to check fileset first, as revset can invoke fileset |
171 similar = _getsimilar(inst.symbols, inst.function) | 191 similar = _getsimilar(inst.symbols, inst.function) |
172 if len(inst.args) > 1: | 192 if len(inst.args) > 1: |
173 write(_("hg: parse error at %s: %s\n") % | 193 write( |
174 (pycompat.bytestr(inst.args[1]), inst.args[0])) | 194 _("hg: parse error at %s: %s\n") |
195 % (pycompat.bytestr(inst.args[1]), inst.args[0]) | |
196 ) | |
175 if inst.args[0].startswith(' '): | 197 if inst.args[0].startswith(' '): |
176 write(_("unexpected leading whitespace\n")) | 198 write(_("unexpected leading whitespace\n")) |
177 else: | 199 else: |
178 write(_("hg: parse error: %s\n") % inst.args[0]) | 200 write(_("hg: parse error: %s\n") % inst.args[0]) |
179 _reportsimilar(write, similar) | 201 _reportsimilar(write, similar) |
180 if inst.hint: | 202 if inst.hint: |
181 write(_("(%s)\n") % inst.hint) | 203 write(_("(%s)\n") % inst.hint) |
182 | 204 |
205 | |
183 def _formatargs(args): | 206 def _formatargs(args): |
184 return ' '.join(procutil.shellquote(a) for a in args) | 207 return ' '.join(procutil.shellquote(a) for a in args) |
208 | |
185 | 209 |
186 def dispatch(req): | 210 def dispatch(req): |
187 """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""" |
188 with tracing.log('dispatch.dispatch'): | 212 with tracing.log('dispatch.dispatch'): |
189 if req.ferr: | 213 if req.ferr: |
246 finally: | 270 finally: |
247 duration = util.timer() - starttime | 271 duration = util.timer() - starttime |
248 req.ui.flush() | 272 req.ui.flush() |
249 if req.ui.logblockedtimes: | 273 if req.ui.logblockedtimes: |
250 req.ui._blockedtimes['command_duration'] = duration * 1000 | 274 req.ui._blockedtimes['command_duration'] = duration * 1000 |
251 req.ui.log('uiblocked', 'ui blocked ms\n', | 275 req.ui.log( |
252 **pycompat.strkwargs(req.ui._blockedtimes)) | 276 'uiblocked', |
277 'ui blocked ms\n', | |
278 **pycompat.strkwargs(req.ui._blockedtimes) | |
279 ) | |
253 return_code = ret & 255 | 280 return_code = ret & 255 |
254 req.ui.log( | 281 req.ui.log( |
255 "commandfinish", | 282 "commandfinish", |
256 "%s exited %d after %0.2f seconds\n", | 283 "%s exited %d after %0.2f seconds\n", |
257 msg, | 284 msg, |
261 duration=duration, | 288 duration=duration, |
262 canonical_command=req.canonical_command, | 289 canonical_command=req.canonical_command, |
263 ) | 290 ) |
264 try: | 291 try: |
265 req._runexithandlers() | 292 req._runexithandlers() |
266 except: # exiting, so no re-raises | 293 except: # exiting, so no re-raises |
267 ret = ret or -1 | 294 ret = ret or -1 |
268 return ret | 295 return ret |
269 | 296 |
297 | |
270 def _runcatch(req): | 298 def _runcatch(req): |
271 with tracing.log('dispatch._runcatch'): | 299 with tracing.log('dispatch._runcatch'): |
300 | |
272 def catchterm(*args): | 301 def catchterm(*args): |
273 raise error.SignalInterrupt | 302 raise error.SignalInterrupt |
274 | 303 |
275 ui = req.ui | 304 ui = req.ui |
276 try: | 305 try: |
277 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': | 306 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': |
278 num = getattr(signal, name, None) | 307 num = getattr(signal, name, None) |
279 if num: | 308 if num: |
280 signal.signal(num, catchterm) | 309 signal.signal(num, catchterm) |
281 except ValueError: | 310 except ValueError: |
282 pass # happens if called in a thread | 311 pass # happens if called in a thread |
283 | 312 |
284 def _runcatchfunc(): | 313 def _runcatchfunc(): |
285 realcmd = None | 314 realcmd = None |
286 try: | 315 try: |
287 cmdargs = fancyopts.fancyopts( | 316 cmdargs = fancyopts.fancyopts( |
288 req.args[:], commands.globalopts, {}) | 317 req.args[:], commands.globalopts, {} |
318 ) | |
289 cmd = cmdargs[0] | 319 cmd = cmdargs[0] |
290 aliases, entry = cmdutil.findcmd(cmd, commands.table, False) | 320 aliases, entry = cmdutil.findcmd(cmd, commands.table, False) |
291 realcmd = aliases[0] | 321 realcmd = aliases[0] |
292 except (error.UnknownCommand, error.AmbiguousCommand, | 322 except ( |
293 IndexError, getopt.GetoptError): | 323 error.UnknownCommand, |
324 error.AmbiguousCommand, | |
325 IndexError, | |
326 getopt.GetoptError, | |
327 ): | |
294 # Don't handle this here. We know the command is | 328 # Don't handle this here. We know the command is |
295 # invalid, but all we're worried about for now is that | 329 # invalid, but all we're worried about for now is that |
296 # it's not a command that server operators expect to | 330 # it's not a command that server operators expect to |
297 # be safe to offer to users in a sandbox. | 331 # be safe to offer to users in a sandbox. |
298 pass | 332 pass |
303 # restrict to exactly that set of arguments, and prohibit | 337 # restrict to exactly that set of arguments, and prohibit |
304 # any repo name that starts with '--' to prevent | 338 # any repo name that starts with '--' to prevent |
305 # shenanigans wherein a user does something like pass | 339 # shenanigans wherein a user does something like pass |
306 # --debugger or --config=ui.debugger=1 as a repo | 340 # --debugger or --config=ui.debugger=1 as a repo |
307 # name. This used to actually run the debugger. | 341 # name. This used to actually run the debugger. |
308 if (len(req.args) != 4 or | 342 if ( |
309 req.args[0] != '-R' or | 343 len(req.args) != 4 |
310 req.args[1].startswith('--') or | 344 or req.args[0] != '-R' |
311 req.args[2] != 'serve' or | 345 or req.args[1].startswith('--') |
312 req.args[3] != '--stdio'): | 346 or req.args[2] != 'serve' |
347 or req.args[3] != '--stdio' | |
348 ): | |
313 raise error.Abort( | 349 raise error.Abort( |
314 _('potentially unsafe serve --stdio invocation: %s') % | 350 _('potentially unsafe serve --stdio invocation: %s') |
315 (stringutil.pprint(req.args),)) | 351 % (stringutil.pprint(req.args),) |
352 ) | |
316 | 353 |
317 try: | 354 try: |
318 debugger = 'pdb' | 355 debugger = 'pdb' |
319 debugtrace = { | 356 debugtrace = {'pdb': pdb.set_trace} |
320 'pdb': pdb.set_trace | 357 debugmortem = {'pdb': pdb.post_mortem} |
321 } | |
322 debugmortem = { | |
323 'pdb': pdb.post_mortem | |
324 } | |
325 | 358 |
326 # read --config before doing anything else | 359 # read --config before doing anything else |
327 # (e.g. to change trust settings for reading .hg/hgrc) | 360 # (e.g. to change trust settings for reading .hg/hgrc) |
328 cfgs = _parseconfig(req.ui, req.earlyoptions['config']) | 361 cfgs = _parseconfig(req.ui, req.earlyoptions['config']) |
329 | 362 |
345 # debugging has been requested | 378 # debugging has been requested |
346 with demandimport.deactivated(): | 379 with demandimport.deactivated(): |
347 try: | 380 try: |
348 debugmod = __import__(debugger) | 381 debugmod = __import__(debugger) |
349 except ImportError: | 382 except ImportError: |
350 pass # Leave debugmod = pdb | 383 pass # Leave debugmod = pdb |
351 | 384 |
352 debugtrace[debugger] = debugmod.set_trace | 385 debugtrace[debugger] = debugmod.set_trace |
353 debugmortem[debugger] = debugmod.post_mortem | 386 debugmortem[debugger] = debugmod.post_mortem |
354 | 387 |
355 # enter the debugger before command execution | 388 # enter the debugger before command execution |
356 if req.earlyoptions['debugger']: | 389 if req.earlyoptions['debugger']: |
357 ui.warn(_("entering debugger - " | 390 ui.warn( |
358 "type c to continue starting hg or h for help\n")) | 391 _( |
359 | 392 "entering debugger - " |
360 if (debugger != 'pdb' and | 393 "type c to continue starting hg or h for help\n" |
361 debugtrace[debugger] == debugtrace['pdb']): | 394 ) |
362 ui.warn(_("%s debugger specified " | 395 ) |
363 "but its module was not found\n") % debugger) | 396 |
397 if ( | |
398 debugger != 'pdb' | |
399 and debugtrace[debugger] == debugtrace['pdb'] | |
400 ): | |
401 ui.warn( | |
402 _( | |
403 "%s debugger specified " | |
404 "but its module was not found\n" | |
405 ) | |
406 % debugger | |
407 ) | |
364 with demandimport.deactivated(): | 408 with demandimport.deactivated(): |
365 debugtrace[debugger]() | 409 debugtrace[debugger]() |
366 try: | 410 try: |
367 return _dispatch(req) | 411 return _dispatch(req) |
368 finally: | 412 finally: |
369 ui.flush() | 413 ui.flush() |
370 except: # re-raises | 414 except: # re-raises |
371 # enter the debugger when we hit an exception | 415 # enter the debugger when we hit an exception |
372 if req.earlyoptions['debugger']: | 416 if req.earlyoptions['debugger']: |
373 traceback.print_exc() | 417 traceback.print_exc() |
374 debugmortem[debugger](sys.exc_info()[2]) | 418 debugmortem[debugger](sys.exc_info()[2]) |
375 raise | 419 raise |
420 | |
376 return _callcatch(ui, _runcatchfunc) | 421 return _callcatch(ui, _runcatchfunc) |
422 | |
377 | 423 |
378 def _callcatch(ui, func): | 424 def _callcatch(ui, func): |
379 """like scmutil.callcatch but handles more high-level exceptions about | 425 """like scmutil.callcatch but handles more high-level exceptions about |
380 config parsing and commands. besides, use handlecommandexception to handle | 426 config parsing and commands. besides, use handlecommandexception to handle |
381 uncaught exceptions. | 427 uncaught exceptions. |
382 """ | 428 """ |
383 try: | 429 try: |
384 return scmutil.callcatch(ui, func) | 430 return scmutil.callcatch(ui, func) |
385 except error.AmbiguousCommand as inst: | 431 except error.AmbiguousCommand as inst: |
386 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") % | 432 ui.warn( |
387 (inst.args[0], " ".join(inst.args[1]))) | 433 _("hg: command '%s' is ambiguous:\n %s\n") |
434 % (inst.args[0], " ".join(inst.args[1])) | |
435 ) | |
388 except error.CommandError as inst: | 436 except error.CommandError as inst: |
389 if inst.args[0]: | 437 if inst.args[0]: |
390 ui.pager('help') | 438 ui.pager('help') |
391 msgbytes = pycompat.bytestr(inst.args[1]) | 439 msgbytes = pycompat.bytestr(inst.args[1]) |
392 ui.warn(_("hg %s: %s\n") % (inst.args[0], msgbytes)) | 440 ui.warn(_("hg %s: %s\n") % (inst.args[0], msgbytes)) |
400 except error.UnknownCommand as inst: | 448 except error.UnknownCommand as inst: |
401 nocmdmsg = _("hg: unknown command '%s'\n") % inst.args[0] | 449 nocmdmsg = _("hg: unknown command '%s'\n") % inst.args[0] |
402 try: | 450 try: |
403 # check if the command is in a disabled extension | 451 # check if the command is in a disabled extension |
404 # (but don't check for extensions themselves) | 452 # (but don't check for extensions themselves) |
405 formatted = help.formattedhelp(ui, commands, inst.args[0], | 453 formatted = help.formattedhelp( |
406 unknowncmd=True) | 454 ui, commands, inst.args[0], unknowncmd=True |
455 ) | |
407 ui.warn(nocmdmsg) | 456 ui.warn(nocmdmsg) |
408 ui.write(formatted) | 457 ui.write(formatted) |
409 except (error.UnknownCommand, error.Abort): | 458 except (error.UnknownCommand, error.Abort): |
410 suggested = False | 459 suggested = False |
411 if len(inst.args) == 2: | 460 if len(inst.args) == 2: |
425 if not handlecommandexception(ui): | 474 if not handlecommandexception(ui): |
426 raise | 475 raise |
427 | 476 |
428 return -1 | 477 return -1 |
429 | 478 |
479 | |
430 def aliasargs(fn, givenargs): | 480 def aliasargs(fn, givenargs): |
431 args = [] | 481 args = [] |
432 # only care about alias 'args', ignore 'args' set by extensions.wrapfunction | 482 # only care about alias 'args', ignore 'args' set by extensions.wrapfunction |
433 if not util.safehasattr(fn, '_origfunc'): | 483 if not util.safehasattr(fn, '_origfunc'): |
434 args = getattr(fn, 'args', args) | 484 args = getattr(fn, 'args', args) |
435 if args: | 485 if args: |
436 cmd = ' '.join(map(procutil.shellquote, args)) | 486 cmd = ' '.join(map(procutil.shellquote, args)) |
437 | 487 |
438 nums = [] | 488 nums = [] |
489 | |
439 def replacer(m): | 490 def replacer(m): |
440 num = int(m.group(1)) - 1 | 491 num = int(m.group(1)) - 1 |
441 nums.append(num) | 492 nums.append(num) |
442 if num < len(givenargs): | 493 if num < len(givenargs): |
443 return givenargs[num] | 494 return givenargs[num] |
444 raise error.Abort(_('too few arguments for command alias')) | 495 raise error.Abort(_('too few arguments for command alias')) |
496 | |
445 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd) | 497 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd) |
446 givenargs = [x for i, x in enumerate(givenargs) | 498 givenargs = [x for i, x in enumerate(givenargs) if i not in nums] |
447 if i not in nums] | |
448 args = pycompat.shlexsplit(cmd) | 499 args = pycompat.shlexsplit(cmd) |
449 return args + givenargs | 500 return args + givenargs |
501 | |
450 | 502 |
451 def aliasinterpolate(name, args, cmd): | 503 def aliasinterpolate(name, args, cmd): |
452 '''interpolate args into cmd for shell aliases | 504 '''interpolate args into cmd for shell aliases |
453 | 505 |
454 This also handles $0, $@ and "$@". | 506 This also handles $0, $@ and "$@". |
467 # escape '\$' for regex | 519 # escape '\$' for regex |
468 regex = '|'.join(replacemap.keys()).replace('$', br'\$') | 520 regex = '|'.join(replacemap.keys()).replace('$', br'\$') |
469 r = re.compile(regex) | 521 r = re.compile(regex) |
470 return r.sub(lambda x: replacemap[x.group()], cmd) | 522 return r.sub(lambda x: replacemap[x.group()], cmd) |
471 | 523 |
524 | |
472 class cmdalias(object): | 525 class cmdalias(object): |
473 def __init__(self, ui, name, definition, cmdtable, source): | 526 def __init__(self, ui, name, definition, cmdtable, source): |
474 self.name = self.cmd = name | 527 self.name = self.cmd = name |
475 self.cmdname = '' | 528 self.cmdname = '' |
476 self.definition = definition | 529 self.definition = definition |
497 return | 550 return |
498 | 551 |
499 if self.definition.startswith('!'): | 552 if self.definition.startswith('!'): |
500 shdef = self.definition[1:] | 553 shdef = self.definition[1:] |
501 self.shell = True | 554 self.shell = True |
555 | |
502 def fn(ui, *args): | 556 def fn(ui, *args): |
503 env = {'HG_ARGS': ' '.join((self.name,) + args)} | 557 env = {'HG_ARGS': ' '.join((self.name,) + args)} |
558 | |
504 def _checkvar(m): | 559 def _checkvar(m): |
505 if m.groups()[0] == '$': | 560 if m.groups()[0] == '$': |
506 return m.group() | 561 return m.group() |
507 elif int(m.groups()[0]) <= len(args): | 562 elif int(m.groups()[0]) <= len(args): |
508 return m.group() | 563 return m.group() |
509 else: | 564 else: |
510 ui.debug("No argument found for substitution " | 565 ui.debug( |
511 "of %i variable in alias '%s' definition.\n" | 566 "No argument found for substitution " |
512 % (int(m.groups()[0]), self.name)) | 567 "of %i variable in alias '%s' definition.\n" |
568 % (int(m.groups()[0]), self.name) | |
569 ) | |
513 return '' | 570 return '' |
571 | |
514 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef) | 572 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef) |
515 cmd = aliasinterpolate(self.name, args, cmd) | 573 cmd = aliasinterpolate(self.name, args, cmd) |
516 return ui.system(cmd, environ=env, | 574 return ui.system( |
517 blockedtag='alias_%s' % self.name) | 575 cmd, environ=env, blockedtag='alias_%s' % self.name |
576 ) | |
577 | |
518 self.fn = fn | 578 self.fn = fn |
519 self.alias = True | 579 self.alias = True |
520 self._populatehelp(ui, name, shdef, self.fn) | 580 self._populatehelp(ui, name, shdef, self.fn) |
521 return | 581 return |
522 | 582 |
523 try: | 583 try: |
524 args = pycompat.shlexsplit(self.definition) | 584 args = pycompat.shlexsplit(self.definition) |
525 except ValueError as inst: | 585 except ValueError as inst: |
526 self.badalias = (_("error in definition for alias '%s': %s") | 586 self.badalias = _("error in definition for alias '%s': %s") % ( |
527 % (self.name, stringutil.forcebytestr(inst))) | 587 self.name, |
588 stringutil.forcebytestr(inst), | |
589 ) | |
528 return | 590 return |
529 earlyopts, args = _earlysplitopts(args) | 591 earlyopts, args = _earlysplitopts(args) |
530 if earlyopts: | 592 if earlyopts: |
531 self.badalias = (_("error in definition for alias '%s': %s may " | 593 self.badalias = _( |
532 "only be given on the command line") | 594 "error in definition for alias '%s': %s may " |
533 % (self.name, '/'.join(pycompat.ziplist(*earlyopts) | 595 "only be given on the command line" |
534 [0]))) | 596 ) % (self.name, '/'.join(pycompat.ziplist(*earlyopts)[0])) |
535 return | 597 return |
536 self.cmdname = cmd = args.pop(0) | 598 self.cmdname = cmd = args.pop(0) |
537 self.givenargs = args | 599 self.givenargs = args |
538 | 600 |
539 try: | 601 try: |
546 | 608 |
547 self.alias = True | 609 self.alias = True |
548 self._populatehelp(ui, name, cmd, self.fn, cmdhelp) | 610 self._populatehelp(ui, name, cmd, self.fn, cmdhelp) |
549 | 611 |
550 except error.UnknownCommand: | 612 except error.UnknownCommand: |
551 self.badalias = (_("alias '%s' resolves to unknown command '%s'") | 613 self.badalias = _("alias '%s' resolves to unknown command '%s'") % ( |
552 % (self.name, cmd)) | 614 self.name, |
615 cmd, | |
616 ) | |
553 self.unknowncmd = True | 617 self.unknowncmd = True |
554 except error.AmbiguousCommand: | 618 except error.AmbiguousCommand: |
555 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'") | 619 self.badalias = _( |
556 % (self.name, cmd)) | 620 "alias '%s' resolves to ambiguous command '%s'" |
621 ) % (self.name, cmd) | |
557 | 622 |
558 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None): | 623 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None): |
559 # confine strings to be passed to i18n.gettext() | 624 # confine strings to be passed to i18n.gettext() |
560 cfg = {} | 625 cfg = {} |
561 for k in ('doc', 'help', 'category'): | 626 for k in ('doc', 'help', 'category'): |
562 v = ui.config('alias', '%s:%s' % (name, k), None) | 627 v = ui.config('alias', '%s:%s' % (name, k), None) |
563 if v is None: | 628 if v is None: |
564 continue | 629 continue |
565 if not encoding.isasciistr(v): | 630 if not encoding.isasciistr(v): |
566 self.badalias = (_("non-ASCII character in alias definition " | 631 self.badalias = _( |
567 "'%s:%s'") % (name, k)) | 632 "non-ASCII character in alias definition " "'%s:%s'" |
633 ) % (name, k) | |
568 return | 634 return |
569 cfg[k] = v | 635 cfg[k] = v |
570 | 636 |
571 self.help = cfg.get('help', defaulthelp or '') | 637 self.help = cfg.get('help', defaulthelp or '') |
572 if self.help and self.help.startswith("hg " + cmd): | 638 if self.help and self.help.startswith("hg " + cmd): |
573 # drop prefix in old-style help lines so hg shows the alias | 639 # drop prefix in old-style help lines so hg shows the alias |
574 self.help = self.help[4 + len(cmd):] | 640 self.help = self.help[4 + len(cmd) :] |
575 | 641 |
576 self.owndoc = 'doc' in cfg | 642 self.owndoc = 'doc' in cfg |
577 doc = cfg.get('doc', pycompat.getdoc(fn)) | 643 doc = cfg.get('doc', pycompat.getdoc(fn)) |
578 if doc is not None: | 644 if doc is not None: |
579 doc = pycompat.sysstr(doc) | 645 doc = pycompat.sysstr(doc) |
585 def args(self): | 651 def args(self): |
586 args = pycompat.maplist(util.expandpath, self.givenargs) | 652 args = pycompat.maplist(util.expandpath, self.givenargs) |
587 return aliasargs(self.fn, args) | 653 return aliasargs(self.fn, args) |
588 | 654 |
589 def __getattr__(self, name): | 655 def __getattr__(self, name): |
590 adefaults = {r'norepo': True, r'intents': set(), | 656 adefaults = { |
591 r'optionalrepo': False, r'inferrepo': False} | 657 r'norepo': True, |
658 r'intents': set(), | |
659 r'optionalrepo': False, | |
660 r'inferrepo': False, | |
661 } | |
592 if name not in adefaults: | 662 if name not in adefaults: |
593 raise AttributeError(name) | 663 raise AttributeError(name) |
594 if self.badalias or util.safehasattr(self, 'shell'): | 664 if self.badalias or util.safehasattr(self, 'shell'): |
595 return adefaults[name] | 665 return adefaults[name] |
596 return getattr(self.fn, name) | 666 return getattr(self.fn, name) |
605 hint = _("'%s' is provided by '%s' extension") % (cmd, ext) | 675 hint = _("'%s' is provided by '%s' extension") % (cmd, ext) |
606 except error.UnknownCommand: | 676 except error.UnknownCommand: |
607 pass | 677 pass |
608 raise error.Abort(self.badalias, hint=hint) | 678 raise error.Abort(self.badalias, hint=hint) |
609 if self.shadows: | 679 if self.shadows: |
610 ui.debug("alias '%s' shadows command '%s'\n" % | 680 ui.debug( |
611 (self.name, self.cmdname)) | 681 "alias '%s' shadows command '%s'\n" % (self.name, self.cmdname) |
612 | 682 ) |
613 ui.log('commandalias', "alias '%s' expands to '%s'\n", | 683 |
614 self.name, self.definition) | 684 ui.log( |
685 'commandalias', | |
686 "alias '%s' expands to '%s'\n", | |
687 self.name, | |
688 self.definition, | |
689 ) | |
615 if util.safehasattr(self, 'shell'): | 690 if util.safehasattr(self, 'shell'): |
616 return self.fn(ui, *args, **opts) | 691 return self.fn(ui, *args, **opts) |
617 else: | 692 else: |
618 try: | 693 try: |
619 return util.checksignature(self.fn)(ui, *args, **opts) | 694 return util.checksignature(self.fn)(ui, *args, **opts) |
620 except error.SignatureError: | 695 except error.SignatureError: |
621 args = ' '.join([self.cmdname] + self.args) | 696 args = ' '.join([self.cmdname] + self.args) |
622 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args)) | 697 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args)) |
623 raise | 698 raise |
624 | 699 |
700 | |
625 class lazyaliasentry(object): | 701 class lazyaliasentry(object): |
626 """like a typical command entry (func, opts, help), but is lazy""" | 702 """like a typical command entry (func, opts, help), but is lazy""" |
627 | 703 |
628 def __init__(self, ui, name, definition, cmdtable, source): | 704 def __init__(self, ui, name, definition, cmdtable, source): |
629 self.ui = ui | 705 self.ui = ui |
633 self.source = source | 709 self.source = source |
634 self.alias = True | 710 self.alias = True |
635 | 711 |
636 @util.propertycache | 712 @util.propertycache |
637 def _aliasdef(self): | 713 def _aliasdef(self): |
638 return cmdalias(self.ui, self.name, self.definition, self.cmdtable, | 714 return cmdalias( |
639 self.source) | 715 self.ui, self.name, self.definition, self.cmdtable, self.source |
716 ) | |
640 | 717 |
641 def __getitem__(self, n): | 718 def __getitem__(self, n): |
642 aliasdef = self._aliasdef | 719 aliasdef = self._aliasdef |
643 if n == 0: | 720 if n == 0: |
644 return aliasdef | 721 return aliasdef |
654 yield self[i] | 731 yield self[i] |
655 | 732 |
656 def __len__(self): | 733 def __len__(self): |
657 return 3 | 734 return 3 |
658 | 735 |
736 | |
659 def addaliases(ui, cmdtable): | 737 def addaliases(ui, cmdtable): |
660 # aliases are processed after extensions have been loaded, so they | 738 # aliases are processed after extensions have been loaded, so they |
661 # may use extension commands. Aliases can also use other alias definitions, | 739 # may use extension commands. Aliases can also use other alias definitions, |
662 # but only if they have been defined prior to the current definition. | 740 # but only if they have been defined prior to the current definition. |
663 for alias, definition in ui.configitems('alias', ignoresub=True): | 741 for alias, definition in ui.configitems('alias', ignoresub=True): |
670 | 748 |
671 source = ui.configsource('alias', alias) | 749 source = ui.configsource('alias', alias) |
672 entry = lazyaliasentry(ui, alias, definition, cmdtable, source) | 750 entry = lazyaliasentry(ui, alias, definition, cmdtable, source) |
673 cmdtable[alias] = entry | 751 cmdtable[alias] = entry |
674 | 752 |
753 | |
675 def _parse(ui, args): | 754 def _parse(ui, args): |
676 options = {} | 755 options = {} |
677 cmdoptions = {} | 756 cmdoptions = {} |
678 | 757 |
679 try: | 758 try: |
681 except getopt.GetoptError as inst: | 760 except getopt.GetoptError as inst: |
682 raise error.CommandError(None, stringutil.forcebytestr(inst)) | 761 raise error.CommandError(None, stringutil.forcebytestr(inst)) |
683 | 762 |
684 if args: | 763 if args: |
685 cmd, args = args[0], args[1:] | 764 cmd, args = args[0], args[1:] |
686 aliases, entry = cmdutil.findcmd(cmd, commands.table, | 765 aliases, entry = cmdutil.findcmd( |
687 ui.configbool("ui", "strict")) | 766 cmd, commands.table, ui.configbool("ui", "strict") |
767 ) | |
688 cmd = aliases[0] | 768 cmd = aliases[0] |
689 args = aliasargs(entry[0], args) | 769 args = aliasargs(entry[0], args) |
690 defaults = ui.config("defaults", cmd) | 770 defaults = ui.config("defaults", cmd) |
691 if defaults: | 771 if defaults: |
692 args = pycompat.maplist( | 772 args = ( |
693 util.expandpath, pycompat.shlexsplit(defaults)) + args | 773 pycompat.maplist(util.expandpath, pycompat.shlexsplit(defaults)) |
774 + args | |
775 ) | |
694 c = list(entry[1]) | 776 c = list(entry[1]) |
695 else: | 777 else: |
696 cmd = None | 778 cmd = None |
697 c = [] | 779 c = [] |
698 | 780 |
711 options[n] = cmdoptions[n] | 793 options[n] = cmdoptions[n] |
712 del cmdoptions[n] | 794 del cmdoptions[n] |
713 | 795 |
714 return (cmd, cmd and entry[0] or None, args, options, cmdoptions) | 796 return (cmd, cmd and entry[0] or None, args, options, cmdoptions) |
715 | 797 |
798 | |
716 def _parseconfig(ui, config): | 799 def _parseconfig(ui, config): |
717 """parse the --config options from the command line""" | 800 """parse the --config options from the command line""" |
718 configs = [] | 801 configs = [] |
719 | 802 |
720 for cfg in config: | 803 for cfg in config: |
721 try: | 804 try: |
722 name, value = [cfgelem.strip() | 805 name, value = [cfgelem.strip() for cfgelem in cfg.split('=', 1)] |
723 for cfgelem in cfg.split('=', 1)] | |
724 section, name = name.split('.', 1) | 806 section, name = name.split('.', 1) |
725 if not section or not name: | 807 if not section or not name: |
726 raise IndexError | 808 raise IndexError |
727 ui.setconfig(section, name, value, '--config') | 809 ui.setconfig(section, name, value, '--config') |
728 configs.append((section, name, value)) | 810 configs.append((section, name, value)) |
729 except (IndexError, ValueError): | 811 except (IndexError, ValueError): |
730 raise error.Abort(_('malformed --config option: %r ' | 812 raise error.Abort( |
731 '(use --config section.name=value)') | 813 _( |
732 % pycompat.bytestr(cfg)) | 814 'malformed --config option: %r ' |
815 '(use --config section.name=value)' | |
816 ) | |
817 % pycompat.bytestr(cfg) | |
818 ) | |
733 | 819 |
734 return configs | 820 return configs |
821 | |
735 | 822 |
736 def _earlyparseopts(ui, args): | 823 def _earlyparseopts(ui, args): |
737 options = {} | 824 options = {} |
738 fancyopts.fancyopts(args, commands.globalopts, options, | 825 fancyopts.fancyopts( |
739 gnu=not ui.plain('strictflags'), early=True, | 826 args, |
740 optaliases={'repository': ['repo']}) | 827 commands.globalopts, |
828 options, | |
829 gnu=not ui.plain('strictflags'), | |
830 early=True, | |
831 optaliases={'repository': ['repo']}, | |
832 ) | |
741 return options | 833 return options |
834 | |
742 | 835 |
743 def _earlysplitopts(args): | 836 def _earlysplitopts(args): |
744 """Split args into a list of possible early options and remainder args""" | 837 """Split args into a list of possible early options and remainder args""" |
745 shortoptions = 'R:' | 838 shortoptions = 'R:' |
746 # TODO: perhaps 'debugger' should be included | 839 # TODO: perhaps 'debugger' should be included |
747 longoptions = ['cwd=', 'repository=', 'repo=', 'config='] | 840 longoptions = ['cwd=', 'repository=', 'repo=', 'config='] |
748 return fancyopts.earlygetopt(args, shortoptions, longoptions, | 841 return fancyopts.earlygetopt( |
749 gnu=True, keepsep=True) | 842 args, shortoptions, longoptions, gnu=True, keepsep=True |
843 ) | |
844 | |
750 | 845 |
751 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions): | 846 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions): |
752 # run pre-hook, and abort if it fails | 847 # run pre-hook, and abort if it fails |
753 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs), | 848 hook.hook( |
754 pats=cmdpats, opts=cmdoptions) | 849 lui, |
850 repo, | |
851 "pre-%s" % cmd, | |
852 True, | |
853 args=" ".join(fullargs), | |
854 pats=cmdpats, | |
855 opts=cmdoptions, | |
856 ) | |
755 try: | 857 try: |
756 ret = _runcommand(ui, options, cmd, d) | 858 ret = _runcommand(ui, options, cmd, d) |
757 # run post-hook, passing command result | 859 # run post-hook, passing command result |
758 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs), | 860 hook.hook( |
759 result=ret, pats=cmdpats, opts=cmdoptions) | 861 lui, |
862 repo, | |
863 "post-%s" % cmd, | |
864 False, | |
865 args=" ".join(fullargs), | |
866 result=ret, | |
867 pats=cmdpats, | |
868 opts=cmdoptions, | |
869 ) | |
760 except Exception: | 870 except Exception: |
761 # run failure hook and re-raise | 871 # run failure hook and re-raise |
762 hook.hook(lui, repo, "fail-%s" % cmd, False, args=" ".join(fullargs), | 872 hook.hook( |
763 pats=cmdpats, opts=cmdoptions) | 873 lui, |
874 repo, | |
875 "fail-%s" % cmd, | |
876 False, | |
877 args=" ".join(fullargs), | |
878 pats=cmdpats, | |
879 opts=cmdoptions, | |
880 ) | |
764 raise | 881 raise |
765 return ret | 882 return ret |
883 | |
766 | 884 |
767 def _getlocal(ui, rpath, wd=None): | 885 def _getlocal(ui, rpath, wd=None): |
768 """Return (path, local ui object) for the given target path. | 886 """Return (path, local ui object) for the given target path. |
769 | 887 |
770 Takes paths in [cwd]/.hg/hgrc into account." | 888 Takes paths in [cwd]/.hg/hgrc into account." |
771 """ | 889 """ |
772 if wd is None: | 890 if wd is None: |
773 try: | 891 try: |
774 wd = encoding.getcwd() | 892 wd = encoding.getcwd() |
775 except OSError as e: | 893 except OSError as e: |
776 raise error.Abort(_("error getting current working directory: %s") % | 894 raise error.Abort( |
777 encoding.strtolocal(e.strerror)) | 895 _("error getting current working directory: %s") |
896 % encoding.strtolocal(e.strerror) | |
897 ) | |
778 path = cmdutil.findrepo(wd) or "" | 898 path = cmdutil.findrepo(wd) or "" |
779 if not path: | 899 if not path: |
780 lui = ui | 900 lui = ui |
781 else: | 901 else: |
782 lui = ui.copy() | 902 lui = ui.copy() |
787 lui = ui.copy() | 907 lui = ui.copy() |
788 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path) | 908 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path) |
789 | 909 |
790 return path, lui | 910 return path, lui |
791 | 911 |
912 | |
792 def _checkshellalias(lui, ui, args): | 913 def _checkshellalias(lui, ui, args): |
793 """Return the function to run the shell alias, if it is required""" | 914 """Return the function to run the shell alias, if it is required""" |
794 options = {} | 915 options = {} |
795 | 916 |
796 try: | 917 try: |
815 | 936 |
816 if cmd and util.safehasattr(fn, 'shell'): | 937 if cmd and util.safehasattr(fn, 'shell'): |
817 # shell alias shouldn't receive early options which are consumed by hg | 938 # shell alias shouldn't receive early options which are consumed by hg |
818 _earlyopts, args = _earlysplitopts(args) | 939 _earlyopts, args = _earlysplitopts(args) |
819 d = lambda: fn(ui, *args[1:]) | 940 d = lambda: fn(ui, *args[1:]) |
820 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d, | 941 return lambda: runcommand( |
821 [], {}) | 942 lui, None, cmd, args[:1], ui, options, d, [], {} |
943 ) | |
944 | |
822 | 945 |
823 def _dispatch(req): | 946 def _dispatch(req): |
824 args = req.args | 947 args = req.args |
825 ui = req.ui | 948 ui = req.ui |
826 | 949 |
835 uis = {ui, lui} | 958 uis = {ui, lui} |
836 | 959 |
837 if req.repo: | 960 if req.repo: |
838 uis.add(req.repo.ui) | 961 uis.add(req.repo.ui) |
839 | 962 |
840 if (req.earlyoptions['verbose'] or req.earlyoptions['debug'] | 963 if ( |
841 or req.earlyoptions['quiet']): | 964 req.earlyoptions['verbose'] |
965 or req.earlyoptions['debug'] | |
966 or req.earlyoptions['quiet'] | |
967 ): | |
842 for opt in ('verbose', 'debug', 'quiet'): | 968 for opt in ('verbose', 'debug', 'quiet'): |
843 val = pycompat.bytestr(bool(req.earlyoptions[opt])) | 969 val = pycompat.bytestr(bool(req.earlyoptions[opt])) |
844 for ui_ in uis: | 970 for ui_ in uis: |
845 ui_.setconfig('ui', opt, val, '--' + opt) | 971 ui_.setconfig('ui', opt, val, '--' + opt) |
846 | 972 |
885 if options["config"] != req.earlyoptions["config"]: | 1011 if options["config"] != req.earlyoptions["config"]: |
886 raise error.Abort(_("option --config may not be abbreviated!")) | 1012 raise error.Abort(_("option --config may not be abbreviated!")) |
887 if options["cwd"] != req.earlyoptions["cwd"]: | 1013 if options["cwd"] != req.earlyoptions["cwd"]: |
888 raise error.Abort(_("option --cwd may not be abbreviated!")) | 1014 raise error.Abort(_("option --cwd may not be abbreviated!")) |
889 if options["repository"] != req.earlyoptions["repository"]: | 1015 if options["repository"] != req.earlyoptions["repository"]: |
890 raise error.Abort(_( | 1016 raise error.Abort( |
891 "option -R has to be separated from other options (e.g. not " | 1017 _( |
892 "-qR) and --repository may only be abbreviated as --repo!")) | 1018 "option -R has to be separated from other options (e.g. not " |
1019 "-qR) and --repository may only be abbreviated as --repo!" | |
1020 ) | |
1021 ) | |
893 if options["debugger"] != req.earlyoptions["debugger"]: | 1022 if options["debugger"] != req.earlyoptions["debugger"]: |
894 raise error.Abort(_("option --debugger may not be abbreviated!")) | 1023 raise error.Abort(_("option --debugger may not be abbreviated!")) |
895 # don't validate --profile/--traceback, which can be enabled from now | 1024 # don't validate --profile/--traceback, which can be enabled from now |
896 | 1025 |
897 if options["encoding"]: | 1026 if options["encoding"]: |
898 encoding.encoding = options["encoding"] | 1027 encoding.encoding = options["encoding"] |
899 if options["encodingmode"]: | 1028 if options["encodingmode"]: |
900 encoding.encodingmode = options["encodingmode"] | 1029 encoding.encodingmode = options["encodingmode"] |
901 if options["time"]: | 1030 if options["time"]: |
1031 | |
902 def get_times(): | 1032 def get_times(): |
903 t = os.times() | 1033 t = os.times() |
904 if t[4] == 0.0: | 1034 if t[4] == 0.0: |
905 # Windows leaves this as zero, so use time.clock() | 1035 # Windows leaves this as zero, so use time.clock() |
906 t = (t[0], t[1], t[2], t[3], time.clock()) | 1036 t = (t[0], t[1], t[2], t[3], time.clock()) |
907 return t | 1037 return t |
1038 | |
908 s = get_times() | 1039 s = get_times() |
1040 | |
909 def print_time(): | 1041 def print_time(): |
910 t = get_times() | 1042 t = get_times() |
911 ui.warn( | 1043 ui.warn( |
912 _("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") % | 1044 _("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") |
913 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3])) | 1045 % ( |
1046 t[4] - s[4], | |
1047 t[0] - s[0], | |
1048 t[2] - s[2], | |
1049 t[1] - s[1], | |
1050 t[3] - s[3], | |
1051 ) | |
1052 ) | |
1053 | |
914 ui.atexit(print_time) | 1054 ui.atexit(print_time) |
915 if options["profile"]: | 1055 if options["profile"]: |
916 profiler.start() | 1056 profiler.start() |
917 | 1057 |
918 # if abbreviated version of this were used, take them in account, now | 1058 # if abbreviated version of this were used, take them in account, now |
975 repo.ui.fout = ui.fout | 1115 repo.ui.fout = ui.fout |
976 repo.ui.ferr = ui.ferr | 1116 repo.ui.ferr = ui.ferr |
977 repo.ui.fmsg = ui.fmsg | 1117 repo.ui.fmsg = ui.fmsg |
978 else: | 1118 else: |
979 try: | 1119 try: |
980 repo = hg.repository(ui, path=path, | 1120 repo = hg.repository( |
981 presetupfuncs=req.prereposetups, | 1121 ui, |
982 intents=func.intents) | 1122 path=path, |
1123 presetupfuncs=req.prereposetups, | |
1124 intents=func.intents, | |
1125 ) | |
983 if not repo.local(): | 1126 if not repo.local(): |
984 raise error.Abort(_("repository '%s' is not local") | 1127 raise error.Abort( |
985 % path) | 1128 _("repository '%s' is not local") % path |
986 repo.ui.setconfig("bundle", "mainreporoot", repo.root, | 1129 ) |
987 'repo') | 1130 repo.ui.setconfig( |
1131 "bundle", "mainreporoot", repo.root, 'repo' | |
1132 ) | |
988 except error.RequirementError: | 1133 except error.RequirementError: |
989 raise | 1134 raise |
990 except error.RepoError: | 1135 except error.RepoError: |
991 if rpath: # invalid -R path | 1136 if rpath: # invalid -R path |
992 raise | 1137 raise |
993 if not func.optionalrepo: | 1138 if not func.optionalrepo: |
994 if func.inferrepo and args and not path: | 1139 if func.inferrepo and args and not path: |
995 # try to infer -R from command args | 1140 # try to infer -R from command args |
996 repos = pycompat.maplist(cmdutil.findrepo, args) | 1141 repos = pycompat.maplist(cmdutil.findrepo, args) |
998 if guess and repos.count(guess) == len(repos): | 1143 if guess and repos.count(guess) == len(repos): |
999 req.args = ['--repository', guess] + fullargs | 1144 req.args = ['--repository', guess] + fullargs |
1000 req.earlyoptions['repository'] = guess | 1145 req.earlyoptions['repository'] = guess |
1001 return _dispatch(req) | 1146 return _dispatch(req) |
1002 if not path: | 1147 if not path: |
1003 raise error.RepoError(_("no repository found in" | 1148 raise error.RepoError( |
1004 " '%s' (.hg not found)") | 1149 _( |
1005 % encoding.getcwd()) | 1150 "no repository found in" |
1151 " '%s' (.hg not found)" | |
1152 ) | |
1153 % encoding.getcwd() | |
1154 ) | |
1006 raise | 1155 raise |
1007 if repo: | 1156 if repo: |
1008 ui = repo.ui | 1157 ui = repo.ui |
1009 if options['hidden']: | 1158 if options['hidden']: |
1010 repo = repo.unfiltered() | 1159 repo = repo.unfiltered() |
1015 msg = _formatargs(fullargs) | 1164 msg = _formatargs(fullargs) |
1016 ui.log("command", '%s\n', msg) | 1165 ui.log("command", '%s\n', msg) |
1017 strcmdopt = pycompat.strkwargs(cmdoptions) | 1166 strcmdopt = pycompat.strkwargs(cmdoptions) |
1018 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt) | 1167 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt) |
1019 try: | 1168 try: |
1020 return runcommand(lui, repo, cmd, fullargs, ui, options, d, | 1169 return runcommand( |
1021 cmdpats, cmdoptions) | 1170 lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions |
1171 ) | |
1022 finally: | 1172 finally: |
1023 if repo and repo != req.repo: | 1173 if repo and repo != req.repo: |
1024 repo.close() | 1174 repo.close() |
1175 | |
1025 | 1176 |
1026 def _runcommand(ui, options, cmd, cmdfunc): | 1177 def _runcommand(ui, options, cmd, cmdfunc): |
1027 """Run a command function, possibly with profiling enabled.""" | 1178 """Run a command function, possibly with profiling enabled.""" |
1028 try: | 1179 try: |
1029 with tracing.log("Running %s command" % cmd): | 1180 with tracing.log("Running %s command" % cmd): |
1030 return cmdfunc() | 1181 return cmdfunc() |
1031 except error.SignatureError: | 1182 except error.SignatureError: |
1032 raise error.CommandError(cmd, _('invalid arguments')) | 1183 raise error.CommandError(cmd, _('invalid arguments')) |
1184 | |
1033 | 1185 |
1034 def _exceptionwarning(ui): | 1186 def _exceptionwarning(ui): |
1035 """Produce a warning message for the current active exception""" | 1187 """Produce a warning message for the current active exception""" |
1036 | 1188 |
1037 # For compatibility checking, we discard the portion of the hg | 1189 # For compatibility checking, we discard the portion of the hg |
1067 if worst[0] is None or nearest < worst[1]: | 1219 if worst[0] is None or nearest < worst[1]: |
1068 worst = name, nearest, report | 1220 worst = name, nearest, report |
1069 if worst[0] is not None: | 1221 if worst[0] is not None: |
1070 name, testedwith, report = worst | 1222 name, testedwith, report = worst |
1071 if not isinstance(testedwith, (bytes, str)): | 1223 if not isinstance(testedwith, (bytes, str)): |
1072 testedwith = '.'.join([stringutil.forcebytestr(c) | 1224 testedwith = '.'.join( |
1073 for c in testedwith]) | 1225 [stringutil.forcebytestr(c) for c in testedwith] |
1074 warning = (_('** Unknown exception encountered with ' | 1226 ) |
1075 'possibly-broken third-party extension %s\n' | 1227 warning = _( |
1076 '** which supports versions %s of Mercurial.\n' | 1228 '** Unknown exception encountered with ' |
1077 '** Please disable %s and try your action again.\n' | 1229 'possibly-broken third-party extension %s\n' |
1078 '** If that fixes the bug please report it to %s\n') | 1230 '** which supports versions %s of Mercurial.\n' |
1079 % (name, testedwith, name, stringutil.forcebytestr(report))) | 1231 '** Please disable %s and try your action again.\n' |
1232 '** If that fixes the bug please report it to %s\n' | |
1233 ) % (name, testedwith, name, stringutil.forcebytestr(report)) | |
1080 else: | 1234 else: |
1081 bugtracker = ui.config('ui', 'supportcontact') | 1235 bugtracker = ui.config('ui', 'supportcontact') |
1082 if bugtracker is None: | 1236 if bugtracker is None: |
1083 bugtracker = _("https://mercurial-scm.org/wiki/BugTracker") | 1237 bugtracker = _("https://mercurial-scm.org/wiki/BugTracker") |
1084 warning = (_("** unknown exception encountered, " | 1238 warning = ( |
1085 "please report by visiting\n** ") + bugtracker + '\n') | 1239 _( |
1240 "** unknown exception encountered, " | |
1241 "please report by visiting\n** " | |
1242 ) | |
1243 + bugtracker | |
1244 + '\n' | |
1245 ) | |
1086 sysversion = pycompat.sysbytes(sys.version).replace('\n', '') | 1246 sysversion = pycompat.sysbytes(sys.version).replace('\n', '') |
1087 warning += ((_("** Python %s\n") % sysversion) + | 1247 warning += ( |
1088 (_("** Mercurial Distributed SCM (version %s)\n") % | 1248 (_("** Python %s\n") % sysversion) |
1089 util.version()) + | 1249 + (_("** Mercurial Distributed SCM (version %s)\n") % util.version()) |
1090 (_("** Extensions loaded: %s\n") % | 1250 + ( |
1091 ", ".join([x[0] for x in extensions.extensions()]))) | 1251 _("** Extensions loaded: %s\n") |
1252 % ", ".join([x[0] for x in extensions.extensions()]) | |
1253 ) | |
1254 ) | |
1092 return warning | 1255 return warning |
1256 | |
1093 | 1257 |
1094 def handlecommandexception(ui): | 1258 def handlecommandexception(ui): |
1095 """Produce a warning message for broken commands | 1259 """Produce a warning message for broken commands |
1096 | 1260 |
1097 Called when handling an exception; the exception is reraised if | 1261 Called when handling an exception; the exception is reraised if |
1098 this function returns False, ignored otherwise. | 1262 this function returns False, ignored otherwise. |
1099 """ | 1263 """ |
1100 warning = _exceptionwarning(ui) | 1264 warning = _exceptionwarning(ui) |
1101 ui.log("commandexception", "%s\n%s\n", warning, | 1265 ui.log( |
1102 pycompat.sysbytes(traceback.format_exc())) | 1266 "commandexception", |
1267 "%s\n%s\n", | |
1268 warning, | |
1269 pycompat.sysbytes(traceback.format_exc()), | |
1270 ) | |
1103 ui.warn(warning) | 1271 ui.warn(warning) |
1104 return False # re-raise the exception | 1272 return False # re-raise the exception |