comparison mercurial/ui.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 51a2e3102db2
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
44 ) 44 )
45 45
46 urlreq = util.urlreq 46 urlreq = util.urlreq
47 47
48 # for use with str.translate(None, _keepalnum), to keep just alphanumerics 48 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
49 _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256)) 49 _keepalnum = ''.join(
50 if not c.isalnum()) 50 c for c in map(pycompat.bytechr, range(256)) if not c.isalnum()
51 )
51 52
52 # The config knobs that will be altered (if unset) by ui.tweakdefaults. 53 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
53 tweakrc = b""" 54 tweakrc = b"""
54 [ui] 55 [ui]
55 # The rollback command is dangerous. As a rule, don't use it. 56 # The rollback command is dangerous. As a rule, don't use it.
76 showfunc = 1 77 showfunc = 1
77 word-diff = 1 78 word-diff = 1
78 """ 79 """
79 80
80 samplehgrcs = { 81 samplehgrcs = {
81 'user': 82 'user': b"""# example user config (see 'hg help config' for more info)
82 b"""# example user config (see 'hg help config' for more info)
83 [ui] 83 [ui]
84 # name and email, e.g. 84 # name and email, e.g.
85 # username = Jane Doe <jdoe@example.com> 85 # username = Jane Doe <jdoe@example.com>
86 username = 86 username =
87 87
104 # 104 #
105 # histedit = 105 # histedit =
106 # rebase = 106 # rebase =
107 # uncommit = 107 # uncommit =
108 """, 108 """,
109 109 'cloned': b"""# example repository config (see 'hg help config' for more info)
110 'cloned':
111 b"""# example repository config (see 'hg help config' for more info)
112 [paths] 110 [paths]
113 default = %s 111 default = %s
114 112
115 # path aliases to other clones of this repo in URLs or filesystem paths 113 # path aliases to other clones of this repo in URLs or filesystem paths
116 # (see 'hg help config.paths' for more info) 114 # (see 'hg help config.paths' for more info)
121 119
122 [ui] 120 [ui]
123 # name and email (local to this repository, optional), e.g. 121 # name and email (local to this repository, optional), e.g.
124 # username = Jane Doe <jdoe@example.com> 122 # username = Jane Doe <jdoe@example.com>
125 """, 123 """,
126 124 'local': b"""# example repository config (see 'hg help config' for more info)
127 'local':
128 b"""# example repository config (see 'hg help config' for more info)
129 [paths] 125 [paths]
130 # path aliases to other clones of this repo in URLs or filesystem paths 126 # path aliases to other clones of this repo in URLs or filesystem paths
131 # (see 'hg help config.paths' for more info) 127 # (see 'hg help config.paths' for more info)
132 # 128 #
133 # default = http://example.com/hg/example-repo 129 # default = http://example.com/hg/example-repo
137 133
138 [ui] 134 [ui]
139 # name and email (local to this repository, optional), e.g. 135 # name and email (local to this repository, optional), e.g.
140 # username = Jane Doe <jdoe@example.com> 136 # username = Jane Doe <jdoe@example.com>
141 """, 137 """,
142 138 'global': b"""# example system-wide hg config (see 'hg help config' for more info)
143 'global':
144 b"""# example system-wide hg config (see 'hg help config' for more info)
145 139
146 [ui] 140 [ui]
147 # uncomment to disable color in command output 141 # uncomment to disable color in command output
148 # (see 'hg help color' for details) 142 # (see 'hg help color' for details)
149 # color = never 143 # color = never
159 # blackbox = 153 # blackbox =
160 # churn = 154 # churn =
161 """, 155 """,
162 } 156 }
163 157
158
164 def _maybestrurl(maybebytes): 159 def _maybestrurl(maybebytes):
165 return pycompat.rapply(pycompat.strurl, maybebytes) 160 return pycompat.rapply(pycompat.strurl, maybebytes)
166 161
162
167 def _maybebytesurl(maybestr): 163 def _maybebytesurl(maybestr):
168 return pycompat.rapply(pycompat.bytesurl, maybestr) 164 return pycompat.rapply(pycompat.bytesurl, maybestr)
169 165
166
170 class httppasswordmgrdbproxy(object): 167 class httppasswordmgrdbproxy(object):
171 """Delays loading urllib2 until it's needed.""" 168 """Delays loading urllib2 until it's needed."""
169
172 def __init__(self): 170 def __init__(self):
173 self._mgr = None 171 self._mgr = None
174 172
175 def _get_mgr(self): 173 def _get_mgr(self):
176 if self._mgr is None: 174 if self._mgr is None:
177 self._mgr = urlreq.httppasswordmgrwithdefaultrealm() 175 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
178 return self._mgr 176 return self._mgr
179 177
180 def add_password(self, realm, uris, user, passwd): 178 def add_password(self, realm, uris, user, passwd):
181 return self._get_mgr().add_password( 179 return self._get_mgr().add_password(
182 _maybestrurl(realm), _maybestrurl(uris), 180 _maybestrurl(realm),
183 _maybestrurl(user), _maybestrurl(passwd)) 181 _maybestrurl(uris),
182 _maybestrurl(user),
183 _maybestrurl(passwd),
184 )
184 185
185 def find_user_password(self, realm, uri): 186 def find_user_password(self, realm, uri):
186 mgr = self._get_mgr() 187 mgr = self._get_mgr()
187 return _maybebytesurl(mgr.find_user_password(_maybestrurl(realm), 188 return _maybebytesurl(
188 _maybestrurl(uri))) 189 mgr.find_user_password(_maybestrurl(realm), _maybestrurl(uri))
190 )
191
189 192
190 def _catchterm(*args): 193 def _catchterm(*args):
191 raise error.SignalInterrupt 194 raise error.SignalInterrupt
195
192 196
193 # unique object used to detect no default value has been provided when 197 # unique object used to detect no default value has been provided when
194 # retrieving configuration value. 198 # retrieving configuration value.
195 _unset = object() 199 _unset = object()
196 200
197 # _reqexithandlers: callbacks run at the end of a request 201 # _reqexithandlers: callbacks run at the end of a request
198 _reqexithandlers = [] 202 _reqexithandlers = []
203
199 204
200 class ui(object): 205 class ui(object):
201 def __init__(self, src=None): 206 def __init__(self, src=None):
202 """Create a fresh new ui object if no src given 207 """Create a fresh new ui object if no src given
203 208
214 # This exists to prevent an extra list lookup. 219 # This exists to prevent an extra list lookup.
215 self._bufferapplylabels = None 220 self._bufferapplylabels = None
216 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False 221 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
217 self._reportuntrusted = True 222 self._reportuntrusted = True
218 self._knownconfig = configitems.coreitems 223 self._knownconfig = configitems.coreitems
219 self._ocfg = config.config() # overlay 224 self._ocfg = config.config() # overlay
220 self._tcfg = config.config() # trusted 225 self._tcfg = config.config() # trusted
221 self._ucfg = config.config() # untrusted 226 self._ucfg = config.config() # untrusted
222 self._trustusers = set() 227 self._trustusers = set()
223 self._trustgroups = set() 228 self._trustgroups = set()
224 self.callhooks = True 229 self.callhooks = True
225 # Insecure server connections requested. 230 # Insecure server connections requested.
226 self.insecureconnections = False 231 self.insecureconnections = False
347 starttime = util.timer() 352 starttime = util.timer()
348 try: 353 try:
349 yield 354 yield
350 finally: 355 finally:
351 self._blockedtimes[key + '_blocked'] += ( 356 self._blockedtimes[key + '_blocked'] += (
352 (util.timer() - starttime) * 1000) 357 util.timer() - starttime
358 ) * 1000
353 359
354 @contextlib.contextmanager 360 @contextlib.contextmanager
355 def uninterruptible(self): 361 def uninterruptible(self):
356 """Mark an operation as unsafe. 362 """Mark an operation as unsafe.
357 363
359 few are risky (for example repair.strip). This context manager 365 few are risky (for example repair.strip). This context manager
360 lets you advise Mercurial that something risky is happening so 366 lets you advise Mercurial that something risky is happening so
361 that control-C etc can be blocked if desired. 367 that control-C etc can be blocked if desired.
362 """ 368 """
363 enabled = self.configbool('experimental', 'nointerrupt') 369 enabled = self.configbool('experimental', 'nointerrupt')
364 if (enabled and 370 if enabled and self.configbool(
365 self.configbool('experimental', 'nointerrupt-interactiveonly')): 371 'experimental', 'nointerrupt-interactiveonly'
372 ):
366 enabled = self.interactive() 373 enabled = self.interactive()
367 if self._uninterruptible or not enabled: 374 if self._uninterruptible or not enabled:
368 # if nointerrupt support is turned off, the process isn't 375 # if nointerrupt support is turned off, the process isn't
369 # interactive, or we're already in an uninterruptible 376 # interactive, or we're already in an uninterruptible
370 # block, do nothing. 377 # block, do nothing.
371 yield 378 yield
372 return 379 return
380
373 def warn(): 381 def warn():
374 self.warn(_("shutting down cleanly\n")) 382 self.warn(_("shutting down cleanly\n"))
375 self.warn( 383 self.warn(
376 _("press ^C again to terminate immediately (dangerous)\n")) 384 _("press ^C again to terminate immediately (dangerous)\n")
385 )
377 return True 386 return True
387
378 with procutil.uninterruptible(warn): 388 with procutil.uninterruptible(warn):
379 try: 389 try:
380 self._uninterruptible = True 390 self._uninterruptible = True
381 yield 391 yield
382 finally: 392 finally:
398 group = util.groupname(st.st_gid) 408 group = util.groupname(st.st_gid)
399 if user in tusers or group in tgroups or user == util.username(): 409 if user in tusers or group in tgroups or user == util.username():
400 return True 410 return True
401 411
402 if self._reportuntrusted: 412 if self._reportuntrusted:
403 self.warn(_('not trusting file %s from untrusted ' 413 self.warn(
404 'user %s, group %s\n') % (f, user, group)) 414 _('not trusting file %s from untrusted ' 'user %s, group %s\n')
415 % (f, user, group)
416 )
405 return False 417 return False
406 418
407 def readconfig(self, filename, root=None, trust=False, 419 def readconfig(
408 sections=None, remap=None): 420 self, filename, root=None, trust=False, sections=None, remap=None
421 ):
409 try: 422 try:
410 fp = open(filename, r'rb') 423 fp = open(filename, r'rb')
411 except IOError: 424 except IOError:
412 if not sections: # ignore unless we were looking for something 425 if not sections: # ignore unless we were looking for something
413 return 426 return
414 raise 427 raise
415 428
416 cfg = config.config() 429 cfg = config.config()
417 trusted = sections or trust or self._trusted(fp, filename) 430 trusted = sections or trust or self._trusted(fp, filename)
423 if trusted: 436 if trusted:
424 raise 437 raise
425 self.warn(_("ignored: %s\n") % stringutil.forcebytestr(inst)) 438 self.warn(_("ignored: %s\n") % stringutil.forcebytestr(inst))
426 439
427 if self.plain(): 440 if self.plain():
428 for k in ('debug', 'fallbackencoding', 'quiet', 'slash', 441 for k in (
429 'logtemplate', 'message-output', 'statuscopies', 'style', 442 'debug',
430 'traceback', 'verbose'): 443 'fallbackencoding',
444 'quiet',
445 'slash',
446 'logtemplate',
447 'message-output',
448 'statuscopies',
449 'style',
450 'traceback',
451 'verbose',
452 ):
431 if k in cfg['ui']: 453 if k in cfg['ui']:
432 del cfg['ui'][k] 454 del cfg['ui'][k]
433 for k, v in cfg.items('defaults'): 455 for k, v in cfg.items('defaults'):
434 del cfg['defaults'][k] 456 del cfg['defaults'][k]
435 for k, v in cfg.items('commands'): 457 for k, v in cfg.items('commands'):
467 continue 489 continue
468 if not p: 490 if not p:
469 continue 491 continue
470 if '%%' in p: 492 if '%%' in p:
471 s = self.configsource('paths', n) or 'none' 493 s = self.configsource('paths', n) or 'none'
472 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n") 494 self.warn(
473 % (n, p, s)) 495 _("(deprecated '%%' in path %s=%s from %s)\n")
496 % (n, p, s)
497 )
474 p = p.replace('%%', '%') 498 p = p.replace('%%', '%')
475 p = util.expandpath(p) 499 p = util.expandpath(p)
476 if not util.hasscheme(p) and not os.path.isabs(p): 500 if not util.hasscheme(p) and not os.path.isabs(p):
477 p = os.path.normpath(os.path.join(root, p)) 501 p = os.path.normpath(os.path.join(root, p))
478 c.set("paths", n, p) 502 c.set("paths", n, p)
483 self.debugflag = self.configbool('ui', 'debug') 507 self.debugflag = self.configbool('ui', 'debug')
484 self.verbose = self.debugflag or self.configbool('ui', 'verbose') 508 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
485 self.quiet = not self.debugflag and self.configbool('ui', 'quiet') 509 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
486 if self.verbose and self.quiet: 510 if self.verbose and self.quiet:
487 self.quiet = self.verbose = False 511 self.quiet = self.verbose = False
488 self._reportuntrusted = self.debugflag or self.configbool("ui", 512 self._reportuntrusted = self.debugflag or self.configbool(
489 "report_untrusted") 513 "ui", "report_untrusted"
514 )
490 self.tracebackflag = self.configbool('ui', 'traceback') 515 self.tracebackflag = self.configbool('ui', 'traceback')
491 self.logblockedtimes = self.configbool('ui', 'logblockedtimes') 516 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
492 517
493 if section in (None, 'trusted'): 518 if section in (None, 'trusted'):
494 # update trust information 519 # update trust information
502 if tracked: 527 if tracked:
503 logger = loggingutil.fileobjectlogger(self._ferr, tracked) 528 logger = loggingutil.fileobjectlogger(self._ferr, tracked)
504 self.setlogger(b'debug', logger) 529 self.setlogger(b'debug', logger)
505 530
506 def backupconfig(self, section, item): 531 def backupconfig(self, section, item):
507 return (self._ocfg.backup(section, item), 532 return (
508 self._tcfg.backup(section, item), 533 self._ocfg.backup(section, item),
509 self._ucfg.backup(section, item),) 534 self._tcfg.backup(section, item),
535 self._ucfg.backup(section, item),
536 )
537
510 def restoreconfig(self, data): 538 def restoreconfig(self, data):
511 self._ocfg.restore(data[0]) 539 self._ocfg.restore(data[0])
512 self._tcfg.restore(data[1]) 540 self._tcfg.restore(data[1])
513 self._ucfg.restore(data[2]) 541 self._ucfg.restore(data[2])
514 542
524 def configsource(self, section, name, untrusted=False): 552 def configsource(self, section, name, untrusted=False):
525 return self._data(untrusted).source(section, name) 553 return self._data(untrusted).source(section, name)
526 554
527 def config(self, section, name, default=_unset, untrusted=False): 555 def config(self, section, name, default=_unset, untrusted=False):
528 """return the plain string version of a config""" 556 """return the plain string version of a config"""
529 value = self._config(section, name, default=default, 557 value = self._config(
530 untrusted=untrusted) 558 section, name, default=default, untrusted=untrusted
559 )
531 if value is _unset: 560 if value is _unset:
532 return None 561 return None
533 return value 562 return value
534 563
535 def _config(self, section, name, default=_unset, untrusted=False): 564 def _config(self, section, name, default=_unset, untrusted=False):
542 if callable(item.default): 571 if callable(item.default):
543 itemdefault = item.default() 572 itemdefault = item.default()
544 else: 573 else:
545 itemdefault = item.default 574 itemdefault = item.default
546 else: 575 else:
547 msg = ("accessing unregistered config item: '%s.%s'") 576 msg = "accessing unregistered config item: '%s.%s'"
548 msg %= (section, name) 577 msg %= (section, name)
549 self.develwarn(msg, 2, 'warn-config-unknown') 578 self.develwarn(msg, 2, 'warn-config-unknown')
550 579
551 if default is _unset: 580 if default is _unset:
552 if item is None: 581 if item is None:
556 msg = "config item requires an explicit default value: '%s.%s'" 585 msg = "config item requires an explicit default value: '%s.%s'"
557 msg %= (section, name) 586 msg %= (section, name)
558 self.develwarn(msg, 2, 'warn-config-default') 587 self.develwarn(msg, 2, 'warn-config-default')
559 else: 588 else:
560 value = itemdefault 589 value = itemdefault
561 elif (item is not None 590 elif (
562 and item.default is not configitems.dynamicdefault 591 item is not None
563 and default != itemdefault): 592 and item.default is not configitems.dynamicdefault
564 msg = ("specifying a mismatched default value for a registered " 593 and default != itemdefault
565 "config item: '%s.%s' '%s'") 594 ):
595 msg = (
596 "specifying a mismatched default value for a registered "
597 "config item: '%s.%s' '%s'"
598 )
566 msg %= (section, name, pycompat.bytestr(default)) 599 msg %= (section, name, pycompat.bytestr(default))
567 self.develwarn(msg, 2, 'warn-config-default') 600 self.develwarn(msg, 2, 'warn-config-default')
568 601
569 for s, n in alternates: 602 for s, n in alternates:
570 candidate = self._data(untrusted).get(s, n, None) 603 candidate = self._data(untrusted).get(s, n, None)
574 607
575 if self.debugflag and not untrusted and self._reportuntrusted: 608 if self.debugflag and not untrusted and self._reportuntrusted:
576 for s, n in alternates: 609 for s, n in alternates:
577 uvalue = self._ucfg.get(s, n) 610 uvalue = self._ucfg.get(s, n)
578 if uvalue is not None and uvalue != value: 611 if uvalue is not None and uvalue != value:
579 self.debug("ignoring untrusted configuration option " 612 self.debug(
580 "%s.%s = %s\n" % (s, n, uvalue)) 613 "ignoring untrusted configuration option "
614 "%s.%s = %s\n" % (s, n, uvalue)
615 )
581 return value 616 return value
582 617
583 def configsuboptions(self, section, name, default=_unset, untrusted=False): 618 def configsuboptions(self, section, name, default=_unset, untrusted=False):
584 """Get a config option and all sub-options. 619 """Get a config option and all sub-options.
585 620
594 data = self._data(untrusted) 629 data = self._data(untrusted)
595 sub = {} 630 sub = {}
596 prefix = '%s:' % name 631 prefix = '%s:' % name
597 for k, v in data.items(section): 632 for k, v in data.items(section):
598 if k.startswith(prefix): 633 if k.startswith(prefix):
599 sub[k[len(prefix):]] = v 634 sub[k[len(prefix) :]] = v
600 635
601 if self.debugflag and not untrusted and self._reportuntrusted: 636 if self.debugflag and not untrusted and self._reportuntrusted:
602 for k, v in sub.items(): 637 for k, v in sub.items():
603 uvalue = self._ucfg.get(section, '%s:%s' % (name, k)) 638 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
604 if uvalue is not None and uvalue != v: 639 if uvalue is not None and uvalue != v:
605 self.debug('ignoring untrusted configuration option ' 640 self.debug(
606 '%s:%s.%s = %s\n' % (section, name, k, uvalue)) 641 'ignoring untrusted configuration option '
642 '%s:%s.%s = %s\n' % (section, name, k, uvalue)
643 )
607 644
608 return main, sub 645 return main, sub
609 646
610 def configpath(self, section, name, default=_unset, untrusted=False): 647 def configpath(self, section, name, default=_unset, untrusted=False):
611 'get a path config item, expanded relative to repo root or config file' 648 'get a path config item, expanded relative to repo root or config file'
649 return default 686 return default
650 if isinstance(v, bool): 687 if isinstance(v, bool):
651 return v 688 return v
652 b = stringutil.parsebool(v) 689 b = stringutil.parsebool(v)
653 if b is None: 690 if b is None:
654 raise error.ConfigError(_("%s.%s is not a boolean ('%s')") 691 raise error.ConfigError(
655 % (section, name, v)) 692 _("%s.%s is not a boolean ('%s')") % (section, name, v)
693 )
656 return b 694 return b
657 695
658 def configwith(self, convert, section, name, default=_unset, 696 def configwith(
659 desc=None, untrusted=False): 697 self, convert, section, name, default=_unset, desc=None, untrusted=False
698 ):
660 """parse a configuration element with a conversion function 699 """parse a configuration element with a conversion function
661 700
662 >>> u = ui(); s = b'foo' 701 >>> u = ui(); s = b'foo'
663 >>> u.setconfig(s, b'float1', b'42') 702 >>> u.setconfig(s, b'float1', b'42')
664 >>> u.configwith(float, s, b'float1') 703 >>> u.configwith(float, s, b'float1')
679 ConfigError: foo.invalid is not a valid womble ('somevalue') 718 ConfigError: foo.invalid is not a valid womble ('somevalue')
680 """ 719 """
681 720
682 v = self.config(section, name, default, untrusted) 721 v = self.config(section, name, default, untrusted)
683 if v is None: 722 if v is None:
684 return v # do not attempt to convert None 723 return v # do not attempt to convert None
685 try: 724 try:
686 return convert(v) 725 return convert(v)
687 except (ValueError, error.ParseError): 726 except (ValueError, error.ParseError):
688 if desc is None: 727 if desc is None:
689 desc = pycompat.sysbytes(convert.__name__) 728 desc = pycompat.sysbytes(convert.__name__)
690 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')") 729 raise error.ConfigError(
691 % (section, name, desc, v)) 730 _("%s.%s is not a valid %s ('%s')") % (section, name, desc, v)
731 )
692 732
693 def configint(self, section, name, default=_unset, untrusted=False): 733 def configint(self, section, name, default=_unset, untrusted=False):
694 """parse a configuration element as an integer 734 """parse a configuration element as an integer
695 735
696 >>> u = ui(); s = b'foo' 736 >>> u = ui(); s = b'foo'
707 Traceback (most recent call last): 747 Traceback (most recent call last):
708 ... 748 ...
709 ConfigError: foo.invalid is not a valid integer ('somevalue') 749 ConfigError: foo.invalid is not a valid integer ('somevalue')
710 """ 750 """
711 751
712 return self.configwith(int, section, name, default, 'integer', 752 return self.configwith(
713 untrusted) 753 int, section, name, default, 'integer', untrusted
754 )
714 755
715 def configbytes(self, section, name, default=_unset, untrusted=False): 756 def configbytes(self, section, name, default=_unset, untrusted=False):
716 """parse a configuration element as a quantity in bytes 757 """parse a configuration element as a quantity in bytes
717 758
718 Units can be specified as b (bytes), k or kb (kilobytes), m or 759 Units can be specified as b (bytes), k or kb (kilobytes), m or
742 if not isinstance(value, bytes): 783 if not isinstance(value, bytes):
743 return value 784 return value
744 try: 785 try:
745 return util.sizetoint(value) 786 return util.sizetoint(value)
746 except error.ParseError: 787 except error.ParseError:
747 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')") 788 raise error.ConfigError(
748 % (section, name, value)) 789 _("%s.%s is not a byte quantity ('%s')")
790 % (section, name, value)
791 )
749 792
750 def configlist(self, section, name, default=_unset, untrusted=False): 793 def configlist(self, section, name, default=_unset, untrusted=False):
751 """parse a configuration element as a list of comma/space separated 794 """parse a configuration element as a list of comma/space separated
752 strings 795 strings
753 796
758 >>> u.setconfig(s, b'list2', b'this, is "a small" , test ') 801 >>> u.setconfig(s, b'list2', b'this, is "a small" , test ')
759 >>> u.configlist(s, b'list2') 802 >>> u.configlist(s, b'list2')
760 ['this', 'is', 'a small', 'test'] 803 ['this', 'is', 'a small', 'test']
761 """ 804 """
762 # default is not always a list 805 # default is not always a list
763 v = self.configwith(config.parselist, section, name, default, 806 v = self.configwith(
764 'list', untrusted) 807 config.parselist, section, name, default, 'list', untrusted
808 )
765 if isinstance(v, bytes): 809 if isinstance(v, bytes):
766 return config.parselist(v) 810 return config.parselist(v)
767 elif v is None: 811 elif v is None:
768 return [] 812 return []
769 return v 813 return v
775 >>> u.setconfig(s, b'date', b'0 0') 819 >>> u.setconfig(s, b'date', b'0 0')
776 >>> u.configdate(s, b'date') 820 >>> u.configdate(s, b'date')
777 (0, 0) 821 (0, 0)
778 """ 822 """
779 if self.config(section, name, default, untrusted): 823 if self.config(section, name, default, untrusted):
780 return self.configwith(dateutil.parsedate, section, name, default, 824 return self.configwith(
781 'date', untrusted) 825 dateutil.parsedate, section, name, default, 'date', untrusted
826 )
782 if default is _unset: 827 if default is _unset:
783 return None 828 return None
784 return default 829 return default
785 830
786 def configdefault(self, section, name): 831 def configdefault(self, section, name):
806 if ignoresub: 851 if ignoresub:
807 items = [i for i in items if ':' not in i[0]] 852 items = [i for i in items if ':' not in i[0]]
808 if self.debugflag and not untrusted and self._reportuntrusted: 853 if self.debugflag and not untrusted and self._reportuntrusted:
809 for k, v in self._ucfg.items(section): 854 for k, v in self._ucfg.items(section):
810 if self._tcfg.get(section, k) != v: 855 if self._tcfg.get(section, k) != v:
811 self.debug("ignoring untrusted configuration option " 856 self.debug(
812 "%s.%s = %s\n" % (section, k, v)) 857 "ignoring untrusted configuration option "
858 "%s.%s = %s\n" % (section, k, v)
859 )
813 return items 860 return items
814 861
815 def walkconfig(self, untrusted=False): 862 def walkconfig(self, untrusted=False):
816 cfg = self._data(untrusted) 863 cfg = self._data(untrusted)
817 for section in cfg.sections(): 864 for section in cfg.sections():
832 The return value can either be 879 The return value can either be
833 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT 880 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
834 - False if feature is disabled by default and not included in HGPLAIN 881 - False if feature is disabled by default and not included in HGPLAIN
835 - True otherwise 882 - True otherwise
836 ''' 883 '''
837 if ('HGPLAIN' not in encoding.environ and 884 if (
838 'HGPLAINEXCEPT' not in encoding.environ): 885 'HGPLAIN' not in encoding.environ
886 and 'HGPLAINEXCEPT' not in encoding.environ
887 ):
839 return False 888 return False
840 exceptions = encoding.environ.get('HGPLAINEXCEPT', 889 exceptions = (
841 '').strip().split(',') 890 encoding.environ.get('HGPLAINEXCEPT', '').strip().split(',')
891 )
842 # TODO: add support for HGPLAIN=+feature,-feature syntax 892 # TODO: add support for HGPLAIN=+feature,-feature syntax
843 if '+strictflags' not in encoding.environ.get('HGPLAIN', '').split(','): 893 if '+strictflags' not in encoding.environ.get('HGPLAIN', '').split(','):
844 exceptions.append('strictflags') 894 exceptions.append('strictflags')
845 if feature and exceptions: 895 if feature and exceptions:
846 return feature not in exceptions 896 return feature not in exceptions
867 return user 917 return user
868 if user is None and self.configbool("ui", "askusername"): 918 if user is None and self.configbool("ui", "askusername"):
869 user = self.prompt(_("enter a commit username:"), default=None) 919 user = self.prompt(_("enter a commit username:"), default=None)
870 if user is None and not self.interactive(): 920 if user is None and not self.interactive():
871 try: 921 try:
872 user = '%s@%s' % (procutil.getuser(), 922 user = '%s@%s' % (
873 encoding.strtolocal(socket.getfqdn())) 923 procutil.getuser(),
924 encoding.strtolocal(socket.getfqdn()),
925 )
874 self.warn(_("no username found, using '%s' instead\n") % user) 926 self.warn(_("no username found, using '%s' instead\n") % user)
875 except KeyError: 927 except KeyError:
876 pass 928 pass
877 if not user: 929 if not user:
878 raise error.Abort(_('no username supplied'), 930 raise error.Abort(
879 hint=_("use 'hg config --edit' " 931 _('no username supplied'),
880 'to set your username')) 932 hint=_("use 'hg config --edit' " 'to set your username'),
933 )
881 if "\n" in user: 934 if "\n" in user:
882 raise error.Abort(_("username %r contains a newline\n") 935 raise error.Abort(
883 % pycompat.bytestr(user)) 936 _("username %r contains a newline\n") % pycompat.bytestr(user)
937 )
884 return user 938 return user
885 939
886 def shortuser(self, user): 940 def shortuser(self, user):
887 """Return a short representation of a user name or email address.""" 941 """Return a short representation of a user name or email address."""
888 if not self.verbose: 942 if not self.verbose:
1041 dest.write(msg) 1095 dest.write(msg)
1042 except IOError as err: 1096 except IOError as err:
1043 raise error.StdioError(err) 1097 raise error.StdioError(err)
1044 finally: 1098 finally:
1045 self._blockedtimes['stdio_blocked'] += ( 1099 self._blockedtimes['stdio_blocked'] += (
1046 (util.timer() - starttime) * 1000) 1100 util.timer() - starttime
1101 ) * 1000
1047 1102
1048 def write_err(self, *args, **opts): 1103 def write_err(self, *args, **opts):
1049 self._write(self._ferr, *args, **opts) 1104 self._write(self._ferr, *args, **opts)
1050 1105
1051 def _write(self, dest, *args, **opts): 1106 def _write(self, dest, *args, **opts):
1085 # stderr may be buffered under win32 when redirected to files, 1140 # stderr may be buffered under win32 when redirected to files,
1086 # including stdout. 1141 # including stdout.
1087 if dest is self._ferr and not getattr(self._ferr, 'closed', False): 1142 if dest is self._ferr and not getattr(self._ferr, 'closed', False):
1088 dest.flush() 1143 dest.flush()
1089 except IOError as err: 1144 except IOError as err:
1090 if (dest is self._ferr 1145 if dest is self._ferr and err.errno in (
1091 and err.errno in (errno.EPIPE, errno.EIO, errno.EBADF)): 1146 errno.EPIPE,
1147 errno.EIO,
1148 errno.EBADF,
1149 ):
1092 # no way to report the error, so ignore it 1150 # no way to report the error, so ignore it
1093 return 1151 return
1094 raise error.StdioError(err) 1152 raise error.StdioError(err)
1095 finally: 1153 finally:
1096 self._blockedtimes['stdio_blocked'] += ( 1154 self._blockedtimes['stdio_blocked'] += (
1097 (util.timer() - starttime) * 1000) 1155 util.timer() - starttime
1156 ) * 1000
1098 1157
1099 def _writemsg(self, dest, *args, **opts): 1158 def _writemsg(self, dest, *args, **opts):
1100 _writemsgwith(self._write, dest, *args, **opts) 1159 _writemsgwith(self._write, dest, *args, **opts)
1101 1160
1102 def _writemsgnobuf(self, dest, *args, **opts): 1161 def _writemsgnobuf(self, dest, *args, **opts):
1117 except IOError as err: 1176 except IOError as err:
1118 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF): 1177 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1119 raise error.StdioError(err) 1178 raise error.StdioError(err)
1120 finally: 1179 finally:
1121 self._blockedtimes['stdio_blocked'] += ( 1180 self._blockedtimes['stdio_blocked'] += (
1122 (util.timer() - starttime) * 1000) 1181 util.timer() - starttime
1182 ) * 1000
1123 1183
1124 def _isatty(self, fh): 1184 def _isatty(self, fh):
1125 if self.configbool('ui', 'nontty'): 1185 if self.configbool('ui', 'nontty'):
1126 return False 1186 return False
1127 return procutil.isatty(fh) 1187 return procutil.isatty(fh)
1173 1233
1174 Args: 1234 Args:
1175 command: The full, non-aliased name of the command. That is, "log" 1235 command: The full, non-aliased name of the command. That is, "log"
1176 not "history, "summary" not "summ", etc. 1236 not "history, "summary" not "summ", etc.
1177 """ 1237 """
1178 if (self._disablepager 1238 if self._disablepager or self.pageractive:
1179 or self.pageractive):
1180 # how pager should do is already determined 1239 # how pager should do is already determined
1181 return 1240 return
1182 1241
1183 if not command.startswith('internal-always-') and ( 1242 if not command.startswith('internal-always-') and (
1184 # explicit --pager=on (= 'internal-always-' prefix) should 1243 # explicit --pager=on (= 'internal-always-' prefix) should
1191 # formatted() will need some adjustment. 1250 # formatted() will need some adjustment.
1192 or not self.formatted() 1251 or not self.formatted()
1193 or self.plain() 1252 or self.plain()
1194 or self._buffers 1253 or self._buffers
1195 # TODO: expose debugger-enabled on the UI object 1254 # TODO: expose debugger-enabled on the UI object
1196 or '--debugger' in pycompat.sysargv): 1255 or '--debugger' in pycompat.sysargv
1256 ):
1197 # We only want to paginate if the ui appears to be 1257 # We only want to paginate if the ui appears to be
1198 # interactive, the user didn't say HGPLAIN or 1258 # interactive, the user didn't say HGPLAIN or
1199 # HGPLAINEXCEPT=pager, and the user didn't specify --debug. 1259 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
1200 return 1260 return
1201 1261
1206 pagerenv = {} 1266 pagerenv = {}
1207 for name, value in rcutil.defaultpagerenv().items(): 1267 for name, value in rcutil.defaultpagerenv().items():
1208 if name not in encoding.environ: 1268 if name not in encoding.environ:
1209 pagerenv[name] = value 1269 pagerenv[name] = value
1210 1270
1211 self.debug('starting pager for command %s\n' % 1271 self.debug(
1212 stringutil.pprint(command)) 1272 'starting pager for command %s\n' % stringutil.pprint(command)
1273 )
1213 self.flush() 1274 self.flush()
1214 1275
1215 wasformatted = self.formatted() 1276 wasformatted = self.formatted()
1216 if util.safehasattr(signal, "SIGPIPE"): 1277 if util.safehasattr(signal, "SIGPIPE"):
1217 signal.signal(signal.SIGPIPE, _catchterm) 1278 signal.signal(signal.SIGPIPE, _catchterm)
1255 # user so we can also get sane bad PAGER behavior. MSYS has 1316 # user so we can also get sane bad PAGER behavior. MSYS has
1256 # `more.exe`, so do a cmd.exe style resolution of the executable to 1317 # `more.exe`, so do a cmd.exe style resolution of the executable to
1257 # determine which one to use. 1318 # determine which one to use.
1258 fullcmd = procutil.findexe(command) 1319 fullcmd = procutil.findexe(command)
1259 if not fullcmd: 1320 if not fullcmd:
1260 self.warn(_("missing pager command '%s', skipping pager\n") 1321 self.warn(
1261 % command) 1322 _("missing pager command '%s', skipping pager\n") % command
1323 )
1262 return False 1324 return False
1263 1325
1264 command = fullcmd 1326 command = fullcmd
1265 1327
1266 try: 1328 try:
1267 pager = subprocess.Popen( 1329 pager = subprocess.Popen(
1268 procutil.tonativestr(command), shell=shell, bufsize=-1, 1330 procutil.tonativestr(command),
1269 close_fds=procutil.closefds, stdin=subprocess.PIPE, 1331 shell=shell,
1270 stdout=procutil.stdout, stderr=procutil.stderr, 1332 bufsize=-1,
1271 env=procutil.tonativeenv(procutil.shellenviron(env))) 1333 close_fds=procutil.closefds,
1334 stdin=subprocess.PIPE,
1335 stdout=procutil.stdout,
1336 stderr=procutil.stderr,
1337 env=procutil.tonativeenv(procutil.shellenviron(env)),
1338 )
1272 except OSError as e: 1339 except OSError as e:
1273 if e.errno == errno.ENOENT and not shell: 1340 if e.errno == errno.ENOENT and not shell:
1274 self.warn(_("missing pager command '%s', skipping pager\n") 1341 self.warn(
1275 % command) 1342 _("missing pager command '%s', skipping pager\n") % command
1343 )
1276 return False 1344 return False
1277 raise 1345 raise
1278 1346
1279 # back up original file descriptors 1347 # back up original file descriptors
1280 stdoutfd = os.dup(procutil.stdout.fileno()) 1348 stdoutfd = os.dup(procutil.stdout.fileno())
1330 the default curses interface (crecord at the moment). 1398 the default curses interface (crecord at the moment).
1331 """ 1399 """
1332 alldefaults = frozenset(["text", "curses"]) 1400 alldefaults = frozenset(["text", "curses"])
1333 1401
1334 featureinterfaces = { 1402 featureinterfaces = {
1335 "chunkselector": [ 1403 "chunkselector": ["text", "curses",],
1336 "text", 1404 "histedit": ["text", "curses",],
1337 "curses",
1338 ],
1339 "histedit": [
1340 "text",
1341 "curses",
1342 ],
1343 } 1405 }
1344 1406
1345 # Feature-specific interface 1407 # Feature-specific interface
1346 if feature not in featureinterfaces.keys(): 1408 if feature not in featureinterfaces.keys():
1347 # Programming error, not user error 1409 # Programming error, not user error
1350 availableinterfaces = frozenset(featureinterfaces[feature]) 1412 availableinterfaces = frozenset(featureinterfaces[feature])
1351 if alldefaults > availableinterfaces: 1413 if alldefaults > availableinterfaces:
1352 # Programming error, not user error. We need a use case to 1414 # Programming error, not user error. We need a use case to
1353 # define the right thing to do here. 1415 # define the right thing to do here.
1354 raise ValueError( 1416 raise ValueError(
1355 "Feature %s does not handle all default interfaces" % 1417 "Feature %s does not handle all default interfaces" % feature
1356 feature) 1418 )
1357 1419
1358 if self.plain() or encoding.environ.get('TERM') == 'dumb': 1420 if self.plain() or encoding.environ.get('TERM') == 'dumb':
1359 return "text" 1421 return "text"
1360 1422
1361 # Default interface for all the features 1423 # Default interface for all the features
1369 if f in availableinterfaces: 1431 if f in availableinterfaces:
1370 choseninterface = f 1432 choseninterface = f
1371 1433
1372 if i is not None and defaultinterface != i: 1434 if i is not None and defaultinterface != i:
1373 if f is not None: 1435 if f is not None:
1374 self.warn(_("invalid value for ui.interface: %s\n") % 1436 self.warn(_("invalid value for ui.interface: %s\n") % (i,))
1375 (i,))
1376 else: 1437 else:
1377 self.warn(_("invalid value for ui.interface: %s (using %s)\n") % 1438 self.warn(
1378 (i, choseninterface)) 1439 _("invalid value for ui.interface: %s (using %s)\n")
1440 % (i, choseninterface)
1441 )
1379 if f is not None and choseninterface != f: 1442 if f is not None and choseninterface != f:
1380 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") % 1443 self.warn(
1381 (feature, f, choseninterface)) 1444 _("invalid value for ui.interface.%s: %s (using %s)\n")
1445 % (feature, f, choseninterface)
1446 )
1382 1447
1383 return choseninterface 1448 return choseninterface
1384 1449
1385 def interactive(self): 1450 def interactive(self):
1386 '''is interactive input allowed? 1451 '''is interactive input allowed?
1445 def _readline(self, prompt=' ', promptopts=None): 1510 def _readline(self, prompt=' ', promptopts=None):
1446 # Replacing stdin/stdout temporarily is a hard problem on Python 3 1511 # Replacing stdin/stdout temporarily is a hard problem on Python 3
1447 # because they have to be text streams with *no buffering*. Instead, 1512 # because they have to be text streams with *no buffering*. Instead,
1448 # we use rawinput() only if call_readline() will be invoked by 1513 # we use rawinput() only if call_readline() will be invoked by
1449 # PyOS_Readline(), so no I/O will be made at Python layer. 1514 # PyOS_Readline(), so no I/O will be made at Python layer.
1450 usereadline = (self._isatty(self._fin) and self._isatty(self._fout) 1515 usereadline = (
1451 and procutil.isstdin(self._fin) 1516 self._isatty(self._fin)
1452 and procutil.isstdout(self._fout)) 1517 and self._isatty(self._fout)
1518 and procutil.isstdin(self._fin)
1519 and procutil.isstdout(self._fout)
1520 )
1453 if usereadline: 1521 if usereadline:
1454 try: 1522 try:
1455 # magically add command line editing support, where 1523 # magically add command line editing support, where
1456 # available 1524 # available
1457 import readline 1525 import readline
1526
1458 # force demandimport to really load the module 1527 # force demandimport to really load the module
1459 readline.read_history_file 1528 readline.read_history_file
1460 # windows sometimes raises something other than ImportError 1529 # windows sometimes raises something other than ImportError
1461 except Exception: 1530 except Exception:
1462 usereadline = False 1531 usereadline = False
1463 1532
1464 if self._colormode == 'win32' or not usereadline: 1533 if self._colormode == 'win32' or not usereadline:
1465 if not promptopts: 1534 if not promptopts:
1466 promptopts = {} 1535 promptopts = {}
1467 self._writemsgnobuf(self._fmsgout, prompt, type='prompt', 1536 self._writemsgnobuf(
1468 **promptopts) 1537 self._fmsgout, prompt, type='prompt', **promptopts
1538 )
1469 self.flush() 1539 self.flush()
1470 prompt = ' ' 1540 prompt = ' '
1471 else: 1541 else:
1472 prompt = self.label(prompt, 'ui.prompt') + ' ' 1542 prompt = self.label(prompt, 'ui.prompt') + ' '
1473 1543
1498 1568
1499 def _prompt(self, msg, **opts): 1569 def _prompt(self, msg, **opts):
1500 default = opts[r'default'] 1570 default = opts[r'default']
1501 if not self.interactive(): 1571 if not self.interactive():
1502 self._writemsg(self._fmsgout, msg, ' ', type='prompt', **opts) 1572 self._writemsg(self._fmsgout, msg, ' ', type='prompt', **opts)
1503 self._writemsg(self._fmsgout, default or '', "\n", 1573 self._writemsg(
1504 type='promptecho') 1574 self._fmsgout, default or '', "\n", type='promptecho'
1575 )
1505 return default 1576 return default
1506 try: 1577 try:
1507 r = self._readline(prompt=msg, promptopts=opts) 1578 r = self._readline(prompt=msg, promptopts=opts)
1508 if not r: 1579 if not r:
1509 r = default 1580 r = default
1534 # choices containing spaces, ASCII, or basically anything 1605 # choices containing spaces, ASCII, or basically anything
1535 # except an ampersand followed by a character. 1606 # except an ampersand followed by a character.
1536 m = re.match(br'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt) 1607 m = re.match(br'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1537 msg = m.group(1) 1608 msg = m.group(1)
1538 choices = [p.strip(' ') for p in m.group(2).split('$$')] 1609 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1610
1539 def choicetuple(s): 1611 def choicetuple(s):
1540 ampidx = s.index('&') 1612 ampidx = s.index('&')
1541 return s[ampidx + 1:ampidx + 2].lower(), s.replace('&', '', 1) 1613 return s[ampidx + 1 : ampidx + 2].lower(), s.replace('&', '', 1)
1614
1542 return (msg, [choicetuple(s) for s in choices]) 1615 return (msg, [choicetuple(s) for s in choices])
1543 1616
1544 def promptchoice(self, prompt, default=0): 1617 def promptchoice(self, prompt, default=0):
1545 """Prompt user with a message, read response, and ensure it matches 1618 """Prompt user with a message, read response, and ensure it matches
1546 one of the provided choices. The prompt is formatted as follows: 1619 one of the provided choices. The prompt is formatted as follows:
1563 1636
1564 def getpass(self, prompt=None, default=None): 1637 def getpass(self, prompt=None, default=None):
1565 if not self.interactive(): 1638 if not self.interactive():
1566 return default 1639 return default
1567 try: 1640 try:
1568 self._writemsg(self._fmsgerr, prompt or _('password: '), 1641 self._writemsg(
1569 type='prompt', password=True) 1642 self._fmsgerr,
1643 prompt or _('password: '),
1644 type='prompt',
1645 password=True,
1646 )
1570 # disable getpass() only if explicitly specified. it's still valid 1647 # disable getpass() only if explicitly specified. it's still valid
1571 # to interact with tty even if fin is not a tty. 1648 # to interact with tty even if fin is not a tty.
1572 with self.timeblockedsection('stdio'): 1649 with self.timeblockedsection('stdio'):
1573 if self.configbool('ui', 'nontty'): 1650 if self.configbool('ui', 'nontty'):
1574 l = self._fin.readline() 1651 l = self._fin.readline()
1617 ''' 1694 '''
1618 if self.debugflag: 1695 if self.debugflag:
1619 self._writemsg(self._fmsgout, type='debug', *msg, **opts) 1696 self._writemsg(self._fmsgout, type='debug', *msg, **opts)
1620 self.log(b'debug', b'%s', b''.join(msg)) 1697 self.log(b'debug', b'%s', b''.join(msg))
1621 1698
1622 def edit(self, text, user, extra=None, editform=None, pending=None, 1699 def edit(
1623 repopath=None, action=None): 1700 self,
1701 text,
1702 user,
1703 extra=None,
1704 editform=None,
1705 pending=None,
1706 repopath=None,
1707 action=None,
1708 ):
1624 if action is None: 1709 if action is None:
1625 self.develwarn('action is None but will soon be a required ' 1710 self.develwarn(
1626 'parameter to ui.edit()') 1711 'action is None but will soon be a required '
1712 'parameter to ui.edit()'
1713 )
1627 extra_defaults = { 1714 extra_defaults = {
1628 'prefix': 'editor', 1715 'prefix': 'editor',
1629 'suffix': '.txt', 1716 'suffix': '.txt',
1630 } 1717 }
1631 if extra is not None: 1718 if extra is not None:
1632 if extra.get('suffix') is not None: 1719 if extra.get('suffix') is not None:
1633 self.develwarn('extra.suffix is not None but will soon be ' 1720 self.develwarn(
1634 'ignored by ui.edit()') 1721 'extra.suffix is not None but will soon be '
1722 'ignored by ui.edit()'
1723 )
1635 extra_defaults.update(extra) 1724 extra_defaults.update(extra)
1636 extra = extra_defaults 1725 extra = extra_defaults
1637 1726
1638 if action == 'diff': 1727 if action == 'diff':
1639 suffix = '.diff' 1728 suffix = '.diff'
1643 suffix = extra['suffix'] 1732 suffix = extra['suffix']
1644 1733
1645 rdir = None 1734 rdir = None
1646 if self.configbool('experimental', 'editortmpinhg'): 1735 if self.configbool('experimental', 'editortmpinhg'):
1647 rdir = repopath 1736 rdir = repopath
1648 (fd, name) = pycompat.mkstemp(prefix='hg-' + extra['prefix'] + '-', 1737 (fd, name) = pycompat.mkstemp(
1649 suffix=suffix, 1738 prefix='hg-' + extra['prefix'] + '-', suffix=suffix, dir=rdir
1650 dir=rdir) 1739 )
1651 try: 1740 try:
1652 f = os.fdopen(fd, r'wb') 1741 f = os.fdopen(fd, r'wb')
1653 f.write(util.tonativeeol(text)) 1742 f.write(util.tonativeeol(text))
1654 f.close() 1743 f.close()
1655 1744
1665 if pending: 1754 if pending:
1666 environ.update({'HG_PENDING': pending}) 1755 environ.update({'HG_PENDING': pending})
1667 1756
1668 editor = self.geteditor() 1757 editor = self.geteditor()
1669 1758
1670 self.system("%s \"%s\"" % (editor, name), 1759 self.system(
1671 environ=environ, 1760 "%s \"%s\"" % (editor, name),
1672 onerr=error.Abort, errprefix=_("edit failed"), 1761 environ=environ,
1673 blockedtag='editor') 1762 onerr=error.Abort,
1763 errprefix=_("edit failed"),
1764 blockedtag='editor',
1765 )
1674 1766
1675 f = open(name, r'rb') 1767 f = open(name, r'rb')
1676 t = util.fromnativeeol(f.read()) 1768 t = util.fromnativeeol(f.read())
1677 f.close() 1769 f.close()
1678 finally: 1770 finally:
1679 os.unlink(name) 1771 os.unlink(name)
1680 1772
1681 return t 1773 return t
1682 1774
1683 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None, 1775 def system(
1684 blockedtag=None): 1776 self,
1777 cmd,
1778 environ=None,
1779 cwd=None,
1780 onerr=None,
1781 errprefix=None,
1782 blockedtag=None,
1783 ):
1685 '''execute shell command with appropriate output stream. command 1784 '''execute shell command with appropriate output stream. command
1686 output will be redirected if fout is not stdout. 1785 output will be redirected if fout is not stdout.
1687 1786
1688 if command fails and onerr is None, return status, else raise onerr 1787 if command fails and onerr is None, return status, else raise onerr
1689 object as exception. 1788 object as exception.
1697 if any(s[1] for s in self._bufferstates): 1796 if any(s[1] for s in self._bufferstates):
1698 out = self 1797 out = self
1699 with self.timeblockedsection(blockedtag): 1798 with self.timeblockedsection(blockedtag):
1700 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out) 1799 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1701 if rc and onerr: 1800 if rc and onerr:
1702 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]), 1801 errmsg = '%s %s' % (
1703 procutil.explainexit(rc)) 1802 os.path.basename(cmd.split(None, 1)[0]),
1803 procutil.explainexit(rc),
1804 )
1704 if errprefix: 1805 if errprefix:
1705 errmsg = '%s: %s' % (errprefix, errmsg) 1806 errmsg = '%s: %s' % (errprefix, errmsg)
1706 raise onerr(errmsg) 1807 raise onerr(errmsg)
1707 return rc 1808 return rc
1708 1809
1724 causetb = traceback.format_tb(cause[2]) 1825 causetb = traceback.format_tb(cause[2])
1725 exctb = traceback.format_tb(exc[2]) 1826 exctb = traceback.format_tb(exc[2])
1726 exconly = traceback.format_exception_only(cause[0], cause[1]) 1827 exconly = traceback.format_exception_only(cause[0], cause[1])
1727 1828
1728 # exclude frame where 'exc' was chained and rethrown from exctb 1829 # exclude frame where 'exc' was chained and rethrown from exctb
1729 self.write_err('Traceback (most recent call last):\n', 1830 self.write_err(
1730 ''.join(exctb[:-1]), 1831 'Traceback (most recent call last):\n',
1731 ''.join(causetb), 1832 ''.join(exctb[:-1]),
1732 ''.join(exconly)) 1833 ''.join(causetb),
1834 ''.join(exconly),
1835 )
1733 else: 1836 else:
1734 output = traceback.format_exception(exc[0], exc[1], exc[2]) 1837 output = traceback.format_exception(exc[0], exc[1], exc[2])
1735 self.write_err(encoding.strtolocal(r''.join(output))) 1838 self.write_err(encoding.strtolocal(r''.join(output)))
1736 return self.tracebackflag or force 1839 return self.tracebackflag or force
1737 1840
1742 # instead default to E to plumb commit messages to 1845 # instead default to E to plumb commit messages to
1743 # avoid confusion. 1846 # avoid confusion.
1744 editor = 'E' 1847 editor = 'E'
1745 else: 1848 else:
1746 editor = 'vi' 1849 editor = 'vi'
1747 return (encoding.environ.get("HGEDITOR") or 1850 return encoding.environ.get("HGEDITOR") or self.config(
1748 self.config("ui", "editor", editor)) 1851 "ui", "editor", editor
1852 )
1749 1853
1750 @util.propertycache 1854 @util.propertycache
1751 def _progbar(self): 1855 def _progbar(self):
1752 """setup the progbar singleton to the ui object""" 1856 """setup the progbar singleton to the ui object"""
1753 if (self.quiet or self.debugflag 1857 if (
1754 or self.configbool('progress', 'disable') 1858 self.quiet
1755 or not progress.shouldprint(self)): 1859 or self.debugflag
1860 or self.configbool('progress', 'disable')
1861 or not progress.shouldprint(self)
1862 ):
1756 return None 1863 return None
1757 return getprogbar(self) 1864 return getprogbar(self)
1758 1865
1759 def _progclear(self): 1866 def _progclear(self):
1760 """clear progress bar output if any. use it before any output""" 1867 """clear progress bar output if any. use it before any output"""
1761 if not haveprogbar(): # nothing loaded yet 1868 if not haveprogbar(): # nothing loaded yet
1762 return 1869 return
1763 if self._progbar is not None and self._progbar.printed: 1870 if self._progbar is not None and self._progbar.printed:
1764 self._progbar.clear() 1871 self._progbar.clear()
1765 1872
1766 def progress(self, topic, pos, item="", unit="", total=None): 1873 def progress(self, topic, pos, item="", unit="", total=None):
1776 Multiple nested topics may be active at a time. 1883 Multiple nested topics may be active at a time.
1777 1884
1778 All topics should be marked closed by setting pos to None at 1885 All topics should be marked closed by setting pos to None at
1779 termination. 1886 termination.
1780 ''' 1887 '''
1781 self.deprecwarn("use ui.makeprogress() instead of ui.progress()", 1888 self.deprecwarn("use ui.makeprogress() instead of ui.progress()", "5.1")
1782 "5.1")
1783 progress = self.makeprogress(topic, unit, total) 1889 progress = self.makeprogress(topic, unit, total)
1784 if pos is not None: 1890 if pos is not None:
1785 progress.update(pos, item=item) 1891 progress.update(pos, item=item)
1786 else: 1892 else:
1787 progress.complete() 1893 progress.complete()
1793 # raw information 1899 # raw information
1794 # TODO: consider porting some useful information (e.g. estimated 1900 # TODO: consider porting some useful information (e.g. estimated
1795 # time) from progbar. we might want to support update delay to 1901 # time) from progbar. we might want to support update delay to
1796 # reduce the cost of transferring progress messages. 1902 # reduce the cost of transferring progress messages.
1797 def updatebar(topic, pos, item, unit, total): 1903 def updatebar(topic, pos, item, unit, total):
1798 self._fmsgerr.write(None, type=b'progress', topic=topic, 1904 self._fmsgerr.write(
1799 pos=pos, item=item, unit=unit, total=total) 1905 None,
1906 type=b'progress',
1907 topic=topic,
1908 pos=pos,
1909 item=item,
1910 unit=unit,
1911 total=total,
1912 )
1913
1800 elif self._progbar is not None: 1914 elif self._progbar is not None:
1801 updatebar = self._progbar.progress 1915 updatebar = self._progbar.progress
1802 else: 1916 else:
1917
1803 def updatebar(topic, pos, item, unit, total): 1918 def updatebar(topic, pos, item, unit, total):
1804 pass 1919 pass
1920
1805 return scmutil.progress(self, updatebar, topic, unit, total) 1921 return scmutil.progress(self, updatebar, topic, unit, total)
1806 1922
1807 def getlogger(self, name): 1923 def getlogger(self, name):
1808 """Returns a logger of the given name; or None if not registered""" 1924 """Returns a logger of the given name; or None if not registered"""
1809 return self._loggers.get(name) 1925 return self._loggers.get(name)
1827 1943
1828 **opts currently has no defined meanings. 1944 **opts currently has no defined meanings.
1829 ''' 1945 '''
1830 if not self._loggers: 1946 if not self._loggers:
1831 return 1947 return
1832 activeloggers = [l for l in self._loggers.itervalues() 1948 activeloggers = [
1833 if l.tracked(event)] 1949 l for l in self._loggers.itervalues() if l.tracked(event)
1950 ]
1834 if not activeloggers: 1951 if not activeloggers:
1835 return 1952 return
1836 msg = msgfmt % msgargs 1953 msg = msgfmt % msgargs
1837 opts = pycompat.byteskwargs(opts) 1954 opts = pycompat.byteskwargs(opts)
1838 # guard against recursion from e.g. ui.debug() 1955 # guard against recursion from e.g. ui.debug()
1866 """ 1983 """
1867 if not self.configbool('devel', 'all-warnings'): 1984 if not self.configbool('devel', 'all-warnings'):
1868 if config is None or not self.configbool('devel', config): 1985 if config is None or not self.configbool('devel', config):
1869 return 1986 return
1870 msg = 'devel-warn: ' + msg 1987 msg = 'devel-warn: ' + msg
1871 stacklevel += 1 # get in develwarn 1988 stacklevel += 1 # get in develwarn
1872 if self.tracebackflag: 1989 if self.tracebackflag:
1873 util.debugstacktrace(msg, stacklevel, self._ferr, self._fout) 1990 util.debugstacktrace(msg, stacklevel, self._ferr, self._fout)
1874 self.log('develwarn', '%s at:\n%s' % 1991 self.log(
1875 (msg, ''.join(util.getstackframes(stacklevel)))) 1992 'develwarn',
1993 '%s at:\n%s' % (msg, ''.join(util.getstackframes(stacklevel))),
1994 )
1876 else: 1995 else:
1877 curframe = inspect.currentframe() 1996 curframe = inspect.currentframe()
1878 calframe = inspect.getouterframes(curframe, 2) 1997 calframe = inspect.getouterframes(curframe, 2)
1879 fname, lineno, fmsg = calframe[stacklevel][1:4] 1998 fname, lineno, fmsg = calframe[stacklevel][1:4]
1880 fname, fmsg = pycompat.sysbytes(fname), pycompat.sysbytes(fmsg) 1999 fname, fmsg = pycompat.sysbytes(fname), pycompat.sysbytes(fmsg)
1881 self.write_err('%s at: %s:%d (%s)\n' 2000 self.write_err('%s at: %s:%d (%s)\n' % (msg, fname, lineno, fmsg))
1882 % (msg, fname, lineno, fmsg)) 2001 self.log(
1883 self.log('develwarn', '%s at: %s:%d (%s)\n', 2002 'develwarn', '%s at: %s:%d (%s)\n', msg, fname, lineno, fmsg
1884 msg, fname, lineno, fmsg) 2003 )
1885 curframe = calframe = None # avoid cycles 2004 curframe = calframe = None # avoid cycles
1886 2005
1887 def deprecwarn(self, msg, version, stacklevel=2): 2006 def deprecwarn(self, msg, version, stacklevel=2):
1888 """issue a deprecation warning 2007 """issue a deprecation warning
1889 2008
1890 - msg: message explaining what is deprecated and how to upgrade, 2009 - msg: message explaining what is deprecated and how to upgrade,
1891 - version: last version where the API will be supported, 2010 - version: last version where the API will be supported,
1892 """ 2011 """
1893 if not (self.configbool('devel', 'all-warnings') 2012 if not (
1894 or self.configbool('devel', 'deprec-warn')): 2013 self.configbool('devel', 'all-warnings')
2014 or self.configbool('devel', 'deprec-warn')
2015 ):
1895 return 2016 return
1896 msg += ("\n(compatibility will be dropped after Mercurial-%s," 2017 msg += (
1897 " update your code.)") % version 2018 "\n(compatibility will be dropped after Mercurial-%s,"
2019 " update your code.)"
2020 ) % version
1898 self.develwarn(msg, stacklevel=stacklevel, config='deprec-warn') 2021 self.develwarn(msg, stacklevel=stacklevel, config='deprec-warn')
1899 2022
1900 def exportableenviron(self): 2023 def exportableenviron(self):
1901 """The environment variables that are safe to export, e.g. through 2024 """The environment variables that are safe to export, e.g. through
1902 hgweb. 2025 hgweb.
1920 # just restoring ui.quiet config to the previous value is not enough 2043 # just restoring ui.quiet config to the previous value is not enough
1921 # as it does not update ui.quiet class member 2044 # as it does not update ui.quiet class member
1922 if ('ui', 'quiet') in overrides: 2045 if ('ui', 'quiet') in overrides:
1923 self.fixconfig(section='ui') 2046 self.fixconfig(section='ui')
1924 2047
2048
1925 class paths(dict): 2049 class paths(dict):
1926 """Represents a collection of paths and their configs. 2050 """Represents a collection of paths and their configs.
1927 2051
1928 Data is initially derived from ui instances and the config files they have 2052 Data is initially derived from ui instances and the config files they have
1929 loaded. 2053 loaded.
1930 """ 2054 """
2055
1931 def __init__(self, ui): 2056 def __init__(self, ui):
1932 dict.__init__(self) 2057 dict.__init__(self)
1933 2058
1934 for name, loc in ui.configitems('paths', ignoresub=True): 2059 for name, loc in ui.configitems('paths', ignoresub=True):
1935 # No location is the same as not existing. 2060 # No location is the same as not existing.
1971 # Try to resolve as a local path or URI. 2096 # Try to resolve as a local path or URI.
1972 try: 2097 try:
1973 # We don't pass sub-options in, so no need to pass ui instance. 2098 # We don't pass sub-options in, so no need to pass ui instance.
1974 return path(None, None, rawloc=name) 2099 return path(None, None, rawloc=name)
1975 except ValueError: 2100 except ValueError:
1976 raise error.RepoError(_('repository %s does not exist') % 2101 raise error.RepoError(_('repository %s does not exist') % name)
1977 name) 2102
1978 2103
1979 _pathsuboptions = {} 2104 _pathsuboptions = {}
2105
1980 2106
1981 def pathsuboption(option, attr): 2107 def pathsuboption(option, attr):
1982 """Decorator used to declare a path sub-option. 2108 """Decorator used to declare a path sub-option.
1983 2109
1984 Arguments are the sub-option name and the attribute it should set on 2110 Arguments are the sub-option name and the attribute it should set on
1990 instance. 2116 instance.
1991 2117
1992 This decorator can be used to perform additional verification of 2118 This decorator can be used to perform additional verification of
1993 sub-options and to change the type of sub-options. 2119 sub-options and to change the type of sub-options.
1994 """ 2120 """
2121
1995 def register(func): 2122 def register(func):
1996 _pathsuboptions[option] = (attr, func) 2123 _pathsuboptions[option] = (attr, func)
1997 return func 2124 return func
2125
1998 return register 2126 return register
2127
1999 2128
2000 @pathsuboption('pushurl', 'pushloc') 2129 @pathsuboption('pushurl', 'pushloc')
2001 def pushurlpathoption(ui, path, value): 2130 def pushurlpathoption(ui, path, value):
2002 u = util.url(value) 2131 u = util.url(value)
2003 # Actually require a URL. 2132 # Actually require a URL.
2006 return None 2135 return None
2007 2136
2008 # Don't support the #foo syntax in the push URL to declare branch to 2137 # Don't support the #foo syntax in the push URL to declare branch to
2009 # push. 2138 # push.
2010 if u.fragment: 2139 if u.fragment:
2011 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; ' 2140 ui.warn(
2012 'ignoring)\n') % path.name) 2141 _('("#fragment" in paths.%s:pushurl not supported; ' 'ignoring)\n')
2142 % path.name
2143 )
2013 u.fragment = None 2144 u.fragment = None
2014 2145
2015 return bytes(u) 2146 return bytes(u)
2147
2016 2148
2017 @pathsuboption('pushrev', 'pushrev') 2149 @pathsuboption('pushrev', 'pushrev')
2018 def pushrevpathoption(ui, path, value): 2150 def pushrevpathoption(ui, path, value):
2019 return value 2151 return value
2152
2020 2153
2021 class path(object): 2154 class path(object):
2022 """Represents an individual path and its configuration.""" 2155 """Represents an individual path and its configuration."""
2023 2156
2024 def __init__(self, ui, name, rawloc=None, suboptions=None): 2157 def __init__(self, ui, name, rawloc=None, suboptions=None):
2051 self.loc = '%s' % u 2184 self.loc = '%s' % u
2052 2185
2053 # When given a raw location but not a symbolic name, validate the 2186 # When given a raw location but not a symbolic name, validate the
2054 # location is valid. 2187 # location is valid.
2055 if not name and not u.scheme and not self._isvalidlocalpath(self.loc): 2188 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
2056 raise ValueError('location is not a URL or path to a local ' 2189 raise ValueError(
2057 'repo: %s' % rawloc) 2190 'location is not a URL or path to a local ' 'repo: %s' % rawloc
2191 )
2058 2192
2059 suboptions = suboptions or {} 2193 suboptions = suboptions or {}
2060 2194
2061 # Now process the sub-options. If a sub-option is registered, its 2195 # Now process the sub-options. If a sub-option is registered, its
2062 # attribute will always be present. The value will be None if there 2196 # attribute will always be present. The value will be None if there
2091 value = getattr(self, attr) 2225 value = getattr(self, attr)
2092 if value is not None: 2226 if value is not None:
2093 d[subopt] = value 2227 d[subopt] = value
2094 return d 2228 return d
2095 2229
2230
2096 # we instantiate one globally shared progress bar to avoid 2231 # we instantiate one globally shared progress bar to avoid
2097 # competing progress bars when multiple UI objects get created 2232 # competing progress bars when multiple UI objects get created
2098 _progresssingleton = None 2233 _progresssingleton = None
2234
2099 2235
2100 def getprogbar(ui): 2236 def getprogbar(ui):
2101 global _progresssingleton 2237 global _progresssingleton
2102 if _progresssingleton is None: 2238 if _progresssingleton is None:
2103 # passing 'ui' object to the singleton is fishy, 2239 # passing 'ui' object to the singleton is fishy,
2104 # this is how the extension used to work but feel free to rework it. 2240 # this is how the extension used to work but feel free to rework it.
2105 _progresssingleton = progress.progbar(ui) 2241 _progresssingleton = progress.progbar(ui)
2106 return _progresssingleton 2242 return _progresssingleton
2107 2243
2244
2108 def haveprogbar(): 2245 def haveprogbar():
2109 return _progresssingleton is not None 2246 return _progresssingleton is not None
2247
2110 2248
2111 def _selectmsgdests(ui): 2249 def _selectmsgdests(ui):
2112 name = ui.config(b'ui', b'message-output') 2250 name = ui.config(b'ui', b'message-output')
2113 if name == b'channel': 2251 if name == b'channel':
2114 if ui.fmsg: 2252 if ui.fmsg:
2121 return ui.fout, ui.ferr 2259 return ui.fout, ui.ferr
2122 if name == b'stderr': 2260 if name == b'stderr':
2123 return ui.ferr, ui.ferr 2261 return ui.ferr, ui.ferr
2124 raise error.Abort(b'invalid ui.message-output destination: %s' % name) 2262 raise error.Abort(b'invalid ui.message-output destination: %s' % name)
2125 2263
2264
2126 def _writemsgwith(write, dest, *args, **opts): 2265 def _writemsgwith(write, dest, *args, **opts):
2127 """Write ui message with the given ui._write*() function 2266 """Write ui message with the given ui._write*() function
2128 2267
2129 The specified message type is translated to 'ui.<type>' label if the dest 2268 The specified message type is translated to 'ui.<type>' label if the dest
2130 isn't a structured channel, so that the message will be colorized. 2269 isn't a structured channel, so that the message will be colorized.