comparison mercurial/dispatch.py @ 43077:687b865b95ad

formatting: byteify all mercurial/ and hgext/ string literals Done with python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py') black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**') # skip-blame mass-reformatting only Differential Revision: https://phab.mercurial-scm.org/D6972
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:48:39 -0400
parents 2372284d9457
children 86e4daa2d54c
comparison
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
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:
219 219
220 try: 220 try:
221 if not req.ui: 221 if not req.ui:
222 req.ui = uimod.ui.load() 222 req.ui = uimod.ui.load()
223 req.earlyoptions.update(_earlyparseopts(req.ui, req.args)) 223 req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
224 if req.earlyoptions['traceback']: 224 if req.earlyoptions[b'traceback']:
225 req.ui.setconfig('ui', 'traceback', 'on', '--traceback') 225 req.ui.setconfig(b'ui', b'traceback', b'on', b'--traceback')
226 226
227 # set ui streams from the request 227 # set ui streams from the request
228 if req.fin: 228 if req.fin:
229 req.ui.fin = req.fin 229 req.ui.fin = req.fin
230 if req.fout: 230 if req.fout:
232 if req.ferr: 232 if req.ferr:
233 req.ui.ferr = req.ferr 233 req.ui.ferr = req.ferr
234 if req.fmsg: 234 if req.fmsg:
235 req.ui.fmsg = req.fmsg 235 req.ui.fmsg = req.fmsg
236 except error.Abort as inst: 236 except error.Abort as inst:
237 ferr.write(_("abort: %s\n") % inst) 237 ferr.write(_(b"abort: %s\n") % inst)
238 if inst.hint: 238 if inst.hint:
239 ferr.write(_("(%s)\n") % inst.hint) 239 ferr.write(_(b"(%s)\n") % inst.hint)
240 return -1 240 return -1
241 except error.ParseError as inst: 241 except error.ParseError as inst:
242 _formatparse(ferr.write, inst) 242 _formatparse(ferr.write, inst)
243 return -1 243 return -1
244 244
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
269 ret = -1 269 ret = -1
270 finally: 270 finally:
271 duration = util.timer() - starttime 271 duration = util.timer() - starttime
272 req.ui.flush() 272 req.ui.flush()
273 if req.ui.logblockedtimes: 273 if req.ui.logblockedtimes:
274 req.ui._blockedtimes['command_duration'] = duration * 1000 274 req.ui._blockedtimes[b'command_duration'] = duration * 1000
275 req.ui.log( 275 req.ui.log(
276 'uiblocked', 276 b'uiblocked',
277 'ui blocked ms\n', 277 b'ui blocked ms\n',
278 **pycompat.strkwargs(req.ui._blockedtimes) 278 **pycompat.strkwargs(req.ui._blockedtimes)
279 ) 279 )
280 return_code = ret & 255 280 return_code = ret & 255
281 req.ui.log( 281 req.ui.log(
282 "commandfinish", 282 b"commandfinish",
283 "%s exited %d after %0.2f seconds\n", 283 b"%s exited %d after %0.2f seconds\n",
284 msg, 284 msg,
285 return_code, 285 return_code,
286 duration, 286 duration,
287 return_code=return_code, 287 return_code=return_code,
288 duration=duration, 288 duration=duration,
294 ret = ret or -1 294 ret = ret or -1
295 return ret 295 return ret
296 296
297 297
298 def _runcatch(req): 298 def _runcatch(req):
299 with tracing.log('dispatch._runcatch'): 299 with tracing.log(b'dispatch._runcatch'):
300 300
301 def catchterm(*args): 301 def catchterm(*args):
302 raise error.SignalInterrupt 302 raise error.SignalInterrupt
303 303
304 ui = req.ui 304 ui = req.ui
305 try: 305 try:
306 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM': 306 for name in b'SIGBREAK', b'SIGHUP', b'SIGTERM':
307 num = getattr(signal, name, None) 307 num = getattr(signal, name, None)
308 if num: 308 if num:
309 signal.signal(num, catchterm) 309 signal.signal(num, catchterm)
310 except ValueError: 310 except ValueError:
311 pass # happens if called in a thread 311 pass # happens if called in a thread
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]()
411 return _dispatch(req) 413 return _dispatch(req)
412 finally: 414 finally:
413 ui.flush() 415 ui.flush()
414 except: # re-raises 416 except: # re-raises
415 # enter the debugger when we hit an exception 417 # enter the debugger when we hit an exception
416 if req.earlyoptions['debugger']: 418 if req.earlyoptions[b'debugger']:
417 traceback.print_exc() 419 traceback.print_exc()
418 debugmortem[debugger](sys.exc_info()[2]) 420 debugmortem[debugger](sys.exc_info()[2])
419 raise 421 raise
420 422
421 return _callcatch(ui, _runcatchfunc) 423 return _callcatch(ui, _runcatchfunc)
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
463 ui.warn(nocmdmsg) 465 ui.warn(nocmdmsg)
464 _reportsimilar(ui.warn, sim) 466 _reportsimilar(ui.warn, sim)
465 suggested = True 467 suggested = True
466 if not suggested: 468 if not suggested:
467 ui.warn(nocmdmsg) 469 ui.warn(nocmdmsg)
468 ui.warn(_("(use 'hg help' for a list of commands)\n")) 470 ui.warn(_(b"(use 'hg help' for a list of commands)\n"))
469 except IOError: 471 except IOError:
470 raise 472 raise
471 except KeyboardInterrupt: 473 except KeyboardInterrupt:
472 raise 474 raise
473 except: # probably re-raises 475 except: # probably re-raises
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
1261 Called when handling an exception; the exception is reraised if 1266 Called when handling an exception; the exception is reraised if
1262 this function returns False, ignored otherwise. 1267 this function returns False, ignored otherwise.
1263 """ 1268 """
1264 warning = _exceptionwarning(ui) 1269 warning = _exceptionwarning(ui)
1265 ui.log( 1270 ui.log(
1266 "commandexception", 1271 b"commandexception",
1267 "%s\n%s\n", 1272 b"%s\n%s\n",
1268 warning, 1273 warning,
1269 pycompat.sysbytes(traceback.format_exc()), 1274 pycompat.sysbytes(traceback.format_exc()),
1270 ) 1275 )
1271 ui.warn(warning) 1276 ui.warn(warning)
1272 return False # re-raise the exception 1277 return False # re-raise the exception