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 |
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'): |
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): |
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 |
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 |
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' |
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): |
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) |
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 |
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. |