Mercurial > hg
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. |