55 resourceutil, |
60 resourceutil, |
56 stringutil, |
61 stringutil, |
57 urlutil, |
62 urlutil, |
58 ) |
63 ) |
59 |
64 |
|
65 _ConfigItems = Dict[Tuple[bytes, bytes], object] # {(section, name) : value} |
60 # The **opts args of the various write() methods can be basically anything, but |
66 # The **opts args of the various write() methods can be basically anything, but |
61 # there's no way to express it as "anything but str". So type it to be the |
67 # there's no way to express it as "anything but str". So type it to be the |
62 # handful of known types that are used. |
68 # handful of known types that are used. |
63 _MsgOpts = Union[bytes, bool, List["_PromptChoice"]] |
69 _MsgOpts = Union[bytes, bool, List["_PromptChoice"]] |
64 _PromptChoice = Tuple[bytes, bytes] |
70 _PromptChoice = Tuple[bytes, bytes] |
|
71 _Tui = TypeVar('_Tui', bound="ui") |
65 |
72 |
66 urlreq = util.urlreq |
73 urlreq = util.urlreq |
67 |
74 |
68 # for use with str.translate(None, _keepalnum), to keep just alphanumerics |
75 # for use with str.translate(None, _keepalnum), to keep just alphanumerics |
69 _keepalnum = b''.join( |
76 _keepalnum: bytes = b''.join( |
70 c for c in map(pycompat.bytechr, range(256)) if not c.isalnum() |
77 c for c in map(pycompat.bytechr, range(256)) if not c.isalnum() |
71 ) |
78 ) |
72 |
79 |
73 # The config knobs that will be altered (if unset) by ui.tweakdefaults. |
80 # The config knobs that will be altered (if unset) by ui.tweakdefaults. |
74 tweakrc = b""" |
81 tweakrc: bytes = b""" |
75 [ui] |
82 [ui] |
76 # The rollback command is dangerous. As a rule, don't use it. |
83 # The rollback command is dangerous. As a rule, don't use it. |
77 rollback = False |
84 rollback = False |
78 # Make `hg status` report copy information |
85 # Make `hg status` report copy information |
79 statuscopies = yes |
86 statuscopies = yes |
208 return _maybebytesurl( |
215 return _maybebytesurl( |
209 mgr.find_user_password(_maybestrurl(realm), _maybestrurl(uri)) |
216 mgr.find_user_password(_maybestrurl(realm), _maybestrurl(uri)) |
210 ) |
217 ) |
211 |
218 |
212 |
219 |
213 def _catchterm(*args): |
220 def _catchterm(*args) -> NoReturn: |
214 raise error.SignalInterrupt |
221 raise error.SignalInterrupt |
215 |
222 |
216 |
223 |
217 # unique object used to detect no default value has been provided when |
224 # unique object used to detect no default value has been provided when |
218 # retrieving configuration value. |
225 # retrieving configuration value. |
219 _unset = object() |
226 _unset = object() |
220 |
227 |
221 # _reqexithandlers: callbacks run at the end of a request |
228 # _reqexithandlers: callbacks run at the end of a request |
222 _reqexithandlers = [] |
229 _reqexithandlers: List = [] |
223 |
230 |
224 |
231 |
225 class ui: |
232 class ui: |
226 def __init__(self, src=None): |
233 def __init__(self, src: Optional["ui"] = None) -> None: |
227 """Create a fresh new ui object if no src given |
234 """Create a fresh new ui object if no src given |
228 |
235 |
229 Use uimod.ui.load() to create a ui which knows global and user configs. |
236 Use uimod.ui.load() to create a ui which knows global and user configs. |
230 In most cases, you should use ui.copy() to create a copy of an existing |
237 In most cases, you should use ui.copy() to create a copy of an existing |
231 ui object. |
238 ui object. |
316 self._exportableenviron = {} |
323 self._exportableenviron = {} |
317 for k in allowed: |
324 for k in allowed: |
318 if k in self.environ: |
325 if k in self.environ: |
319 self._exportableenviron[k] = self.environ[k] |
326 self._exportableenviron[k] = self.environ[k] |
320 |
327 |
321 def _new_source(self): |
328 def _new_source(self) -> None: |
322 self._ocfg.new_source() |
329 self._ocfg.new_source() |
323 self._tcfg.new_source() |
330 self._tcfg.new_source() |
324 self._ucfg.new_source() |
331 self._ucfg.new_source() |
325 |
332 |
326 @classmethod |
333 @classmethod |
327 def load(cls): |
334 def load(cls: Type[_Tui]) -> _Tui: |
328 """Create a ui and load global and user configs""" |
335 """Create a ui and load global and user configs""" |
329 u = cls() |
336 u = cls() |
330 # we always trust global config files and environment variables |
337 # we always trust global config files and environment variables |
331 for t, f in rcutil.rccomponents(): |
338 for t, f in rcutil.rccomponents(): |
332 if t == b'path': |
339 if t == b'path': |
348 raise error.ProgrammingError(b'unknown rctype: %s' % t) |
355 raise error.ProgrammingError(b'unknown rctype: %s' % t) |
349 u._maybetweakdefaults() |
356 u._maybetweakdefaults() |
350 u._new_source() # anything after that is a different level |
357 u._new_source() # anything after that is a different level |
351 return u |
358 return u |
352 |
359 |
353 def _maybetweakdefaults(self): |
360 def _maybetweakdefaults(self) -> None: |
354 if not self.configbool(b'ui', b'tweakdefaults'): |
361 if not self.configbool(b'ui', b'tweakdefaults'): |
355 return |
362 return |
356 if self._tweaked or self.plain(b'tweakdefaults'): |
363 if self._tweaked or self.plain(b'tweakdefaults'): |
357 return |
364 return |
358 |
365 |
368 for section in tmpcfg: |
375 for section in tmpcfg: |
369 for name, value in tmpcfg.items(section): |
376 for name, value in tmpcfg.items(section): |
370 if not self.hasconfig(section, name): |
377 if not self.hasconfig(section, name): |
371 self.setconfig(section, name, value, b"<tweakdefaults>") |
378 self.setconfig(section, name, value, b"<tweakdefaults>") |
372 |
379 |
373 def copy(self): |
380 def copy(self: _Tui) -> _Tui: |
374 return self.__class__(self) |
381 return self.__class__(self) |
375 |
382 |
376 def resetstate(self): |
383 def resetstate(self) -> None: |
377 """Clear internal state that shouldn't persist across commands""" |
384 """Clear internal state that shouldn't persist across commands""" |
378 if self._progbar: |
385 if self._progbar: |
379 self._progbar.resetstate() # reset last-print time of progress bar |
386 self._progbar.resetstate() # reset last-print time of progress bar |
380 self.httppasswordmgrdb = httppasswordmgrdbproxy() |
387 self.httppasswordmgrdb = httppasswordmgrdbproxy() |
381 |
388 |
382 @contextlib.contextmanager |
389 @contextlib.contextmanager |
383 def timeblockedsection(self, key): |
390 def timeblockedsection(self, key: bytes): |
384 # this is open-coded below - search for timeblockedsection to find them |
391 # this is open-coded below - search for timeblockedsection to find them |
385 starttime = util.timer() |
392 starttime = util.timer() |
386 try: |
393 try: |
387 yield |
394 yield |
388 finally: |
395 finally: |
423 self._uninterruptible = True |
430 self._uninterruptible = True |
424 yield |
431 yield |
425 finally: |
432 finally: |
426 self._uninterruptible = False |
433 self._uninterruptible = False |
427 |
434 |
428 def formatter(self, topic, opts): |
435 def formatter(self, topic: bytes, opts): |
429 return formatter.formatter(self, self, topic, opts) |
436 return formatter.formatter(self, self, topic, opts) |
430 |
437 |
431 def _trusted(self, fp, f): |
438 def _trusted(self, fp, f: bytes) -> bool: |
432 st = util.fstat(fp) |
439 st = util.fstat(fp) |
433 if util.isowner(st): |
440 if util.isowner(st): |
434 return True |
441 return True |
435 |
442 |
436 tusers, tgroups = self._trustusers, self._trustgroups |
443 tusers, tgroups = self._trustusers, self._trustgroups |
452 ) |
459 ) |
453 return False |
460 return False |
454 |
461 |
455 def read_resource_config( |
462 def read_resource_config( |
456 self, name, root=None, trust=False, sections=None, remap=None |
463 self, name, root=None, trust=False, sections=None, remap=None |
457 ): |
464 ) -> None: |
458 try: |
465 try: |
459 fp = resourceutil.open_resource(name[0], name[1]) |
466 fp = resourceutil.open_resource(name[0], name[1]) |
460 except IOError: |
467 except IOError: |
461 if not sections: # ignore unless we were looking for something |
468 if not sections: # ignore unless we were looking for something |
462 return |
469 return |
466 b'resource:%s.%s' % name, fp, root, trust, sections, remap |
473 b'resource:%s.%s' % name, fp, root, trust, sections, remap |
467 ) |
474 ) |
468 |
475 |
469 def readconfig( |
476 def readconfig( |
470 self, filename, root=None, trust=False, sections=None, remap=None |
477 self, filename, root=None, trust=False, sections=None, remap=None |
471 ): |
478 ) -> None: |
472 try: |
479 try: |
473 fp = open(filename, 'rb') |
480 fp = open(filename, 'rb') |
474 except IOError: |
481 except IOError: |
475 if not sections: # ignore unless we were looking for something |
482 if not sections: # ignore unless we were looking for something |
476 return |
483 return |
478 |
485 |
479 self._readconfig(filename, fp, root, trust, sections, remap) |
486 self._readconfig(filename, fp, root, trust, sections, remap) |
480 |
487 |
481 def _readconfig( |
488 def _readconfig( |
482 self, filename, fp, root=None, trust=False, sections=None, remap=None |
489 self, filename, fp, root=None, trust=False, sections=None, remap=None |
483 ): |
490 ) -> None: |
484 with fp: |
491 with fp: |
485 cfg = config.config() |
492 cfg = config.config() |
486 trusted = sections or trust or self._trusted(fp, filename) |
493 trusted = sections or trust or self._trusted(fp, filename) |
487 |
494 |
488 try: |
495 try: |
494 _(b'ignored %s: %s\n') % (inst.location, inst.message) |
501 _(b'ignored %s: %s\n') % (inst.location, inst.message) |
495 ) |
502 ) |
496 |
503 |
497 self._applyconfig(cfg, trusted, root) |
504 self._applyconfig(cfg, trusted, root) |
498 |
505 |
499 def applyconfig(self, configitems, source=b"", root=None): |
506 def applyconfig( |
|
507 self, configitems: _ConfigItems, source=b"", root=None |
|
508 ) -> None: |
500 """Add configitems from a non-file source. Unlike with ``setconfig()``, |
509 """Add configitems from a non-file source. Unlike with ``setconfig()``, |
501 they can be overridden by subsequent config file reads. The items are |
510 they can be overridden by subsequent config file reads. The items are |
502 in the same format as ``configoverride()``, namely a dict of the |
511 in the same format as ``configoverride()``, namely a dict of the |
503 following structures: {(section, name) : value} |
512 following structures: {(section, name) : value} |
504 |
513 |
510 for (section, name), value in configitems.items(): |
519 for (section, name), value in configitems.items(): |
511 cfg.set(section, name, value, source) |
520 cfg.set(section, name, value, source) |
512 |
521 |
513 self._applyconfig(cfg, True, root) |
522 self._applyconfig(cfg, True, root) |
514 |
523 |
515 def _applyconfig(self, cfg, trusted, root): |
524 def _applyconfig(self, cfg, trusted, root) -> None: |
516 if self.plain(): |
525 if self.plain(): |
517 for k in ( |
526 for k in ( |
518 b'debug', |
527 b'debug', |
519 b'fallbackencoding', |
528 b'fallbackencoding', |
520 b'quiet', |
529 b'quiet', |
553 |
562 |
554 if root is None: |
563 if root is None: |
555 root = os.path.expanduser(b'~') |
564 root = os.path.expanduser(b'~') |
556 self.fixconfig(root=root) |
565 self.fixconfig(root=root) |
557 |
566 |
558 def fixconfig(self, root=None, section=None): |
567 def fixconfig(self, root=None, section=None) -> None: |
559 if section in (None, b'paths'): |
568 if section in (None, b'paths'): |
560 # expand vars and ~ |
569 # expand vars and ~ |
561 # translate paths relative to root (or home) into absolute paths |
570 # translate paths relative to root (or home) into absolute paths |
562 root = root or encoding.getcwd() |
571 root = root or encoding.getcwd() |
563 for c in self._tcfg, self._ucfg, self._ocfg: |
572 for c in self._tcfg, self._ucfg, self._ocfg: |
616 self._ocfg.backup(section, item), |
625 self._ocfg.backup(section, item), |
617 self._tcfg.backup(section, item), |
626 self._tcfg.backup(section, item), |
618 self._ucfg.backup(section, item), |
627 self._ucfg.backup(section, item), |
619 ) |
628 ) |
620 |
629 |
621 def restoreconfig(self, data): |
630 def restoreconfig(self, data) -> None: |
622 self._ocfg.restore(data[0]) |
631 self._ocfg.restore(data[0]) |
623 self._tcfg.restore(data[1]) |
632 self._tcfg.restore(data[1]) |
624 self._ucfg.restore(data[2]) |
633 self._ucfg.restore(data[2]) |
625 |
634 |
626 def setconfig(self, section, name, value, source=b''): |
635 def setconfig(self, section, name, value, source=b'') -> None: |
627 for cfg in (self._ocfg, self._tcfg, self._ucfg): |
636 for cfg in (self._ocfg, self._tcfg, self._ucfg): |
628 cfg.set(section, name, value, source) |
637 cfg.set(section, name, value, source) |
629 self.fixconfig(section=section) |
638 self.fixconfig(section=section) |
630 self._maybetweakdefaults() |
639 self._maybetweakdefaults() |
631 |
640 |
1007 cfg = self._data(untrusted) |
1016 cfg = self._data(untrusted) |
1008 for section in cfg.sections(): |
1017 for section in cfg.sections(): |
1009 for name, value in self.configitems(section, untrusted): |
1018 for name, value in self.configitems(section, untrusted): |
1010 yield section, name, value |
1019 yield section, name, value |
1011 |
1020 |
1012 def plain(self, feature=None): |
1021 def plain(self, feature: Optional[bytes] = None) -> bool: |
1013 """is plain mode active? |
1022 """is plain mode active? |
1014 |
1023 |
1015 Plain mode means that all configuration variables which affect |
1024 Plain mode means that all configuration variables which affect |
1016 the behavior and output of Mercurial should be |
1025 the behavior and output of Mercurial should be |
1017 ignored. Additionally, the output should be stable, |
1026 ignored. Additionally, the output should be stable, |
1081 raise error.Abort( |
1090 raise error.Abort( |
1082 _(b"username %r contains a newline\n") % pycompat.bytestr(user) |
1091 _(b"username %r contains a newline\n") % pycompat.bytestr(user) |
1083 ) |
1092 ) |
1084 return user |
1093 return user |
1085 |
1094 |
1086 def shortuser(self, user): |
1095 def shortuser(self, user: bytes) -> bytes: |
1087 """Return a short representation of a user name or email address.""" |
1096 """Return a short representation of a user name or email address.""" |
1088 if not self.verbose: |
1097 if not self.verbose: |
1089 user = stringutil.shortuser(user) |
1098 user = stringutil.shortuser(user) |
1090 return user |
1099 return user |
1091 |
1100 |
1159 def fmsg(self, f): |
1168 def fmsg(self, f): |
1160 self._fmsg = f |
1169 self._fmsg = f |
1161 self._fmsgout, self._fmsgerr = _selectmsgdests(self) |
1170 self._fmsgout, self._fmsgerr = _selectmsgdests(self) |
1162 |
1171 |
1163 @contextlib.contextmanager |
1172 @contextlib.contextmanager |
1164 def silent(self, error=False, subproc=False, labeled=False): |
1173 def silent( |
|
1174 self, error: bool = False, subproc: bool = False, labeled: bool = False |
|
1175 ): |
1165 self.pushbuffer(error=error, subproc=subproc, labeled=labeled) |
1176 self.pushbuffer(error=error, subproc=subproc, labeled=labeled) |
1166 try: |
1177 try: |
1167 yield |
1178 yield |
1168 finally: |
1179 finally: |
1169 self.popbuffer() |
1180 self.popbuffer() |
1170 |
1181 |
1171 def pushbuffer(self, error=False, subproc=False, labeled=False): |
1182 def pushbuffer( |
|
1183 self, error: bool = False, subproc: bool = False, labeled: bool = False |
|
1184 ) -> None: |
1172 """install a buffer to capture standard output of the ui object |
1185 """install a buffer to capture standard output of the ui object |
1173 |
1186 |
1174 If error is True, the error output will be captured too. |
1187 If error is True, the error output will be captured too. |
1175 |
1188 |
1176 If subproc is True, output from subprocesses (typically hooks) will be |
1189 If subproc is True, output from subprocesses (typically hooks) will be |
1185 """ |
1198 """ |
1186 self._buffers.append([]) |
1199 self._buffers.append([]) |
1187 self._bufferstates.append((error, subproc, labeled)) |
1200 self._bufferstates.append((error, subproc, labeled)) |
1188 self._bufferapplylabels = labeled |
1201 self._bufferapplylabels = labeled |
1189 |
1202 |
1190 def popbuffer(self): |
1203 def popbuffer(self) -> bytes: |
1191 '''pop the last buffer and return the buffered output''' |
1204 '''pop the last buffer and return the buffered output''' |
1192 self._bufferstates.pop() |
1205 self._bufferstates.pop() |
1193 if self._bufferstates: |
1206 if self._bufferstates: |
1194 self._bufferapplylabels = self._bufferstates[-1][2] |
1207 self._bufferapplylabels = self._bufferstates[-1][2] |
1195 else: |
1208 else: |
1196 self._bufferapplylabels = None |
1209 self._bufferapplylabels = None |
1197 |
1210 |
1198 return b"".join(self._buffers.pop()) |
1211 return b"".join(self._buffers.pop()) |
1199 |
1212 |
1200 def _isbuffered(self, dest): |
1213 def _isbuffered(self, dest) -> bool: |
1201 if dest is self._fout: |
1214 if dest is self._fout: |
1202 return bool(self._buffers) |
1215 return bool(self._buffers) |
1203 if dest is self._ferr: |
1216 if dest is self._ferr: |
1204 return bool(self._bufferstates and self._bufferstates[-1][0]) |
1217 return bool(self._bufferstates and self._bufferstates[-1][0]) |
1205 return False |
1218 return False |
1206 |
1219 |
1207 def canwritewithoutlabels(self): |
1220 def canwritewithoutlabels(self) -> bool: |
1208 '''check if write skips the label''' |
1221 '''check if write skips the label''' |
1209 if self._buffers and not self._bufferapplylabels: |
1222 if self._buffers and not self._bufferapplylabels: |
1210 return True |
1223 return True |
1211 return self._colormode is None |
1224 return self._colormode is None |
1212 |
1225 |
1213 def canbatchlabeledwrites(self): |
1226 def canbatchlabeledwrites(self) -> bool: |
1214 '''check if write calls with labels are batchable''' |
1227 '''check if write calls with labels are batchable''' |
1215 # Windows color printing is special, see ``write``. |
1228 # Windows color printing is special, see ``write``. |
1216 return self._colormode != b'win32' |
1229 return self._colormode != b'win32' |
1217 |
1230 |
1218 def write(self, *args: bytes, **opts: _MsgOpts) -> None: |
1231 def write(self, *args: bytes, **opts: _MsgOpts) -> None: |
1367 finally: |
1380 finally: |
1368 self._blockedtimes[b'stdio_blocked'] += ( |
1381 self._blockedtimes[b'stdio_blocked'] += ( |
1369 util.timer() - starttime |
1382 util.timer() - starttime |
1370 ) * 1000 |
1383 ) * 1000 |
1371 |
1384 |
1372 def _isatty(self, fh): |
1385 def _isatty(self, fh) -> bool: |
1373 if self.configbool(b'ui', b'nontty'): |
1386 if self.configbool(b'ui', b'nontty'): |
1374 return False |
1387 return False |
1375 return procutil.isatty(fh) |
1388 return procutil.isatty(fh) |
1376 |
1389 |
1377 def protectfinout(self): |
1390 def protectfinout(self): |
1405 try: |
1418 try: |
1406 yield fin, fout |
1419 yield fin, fout |
1407 finally: |
1420 finally: |
1408 self.restorefinout(fin, fout) |
1421 self.restorefinout(fin, fout) |
1409 |
1422 |
1410 def disablepager(self): |
1423 def disablepager(self) -> None: |
1411 self._disablepager = True |
1424 self._disablepager = True |
1412 |
1425 |
1413 def pager(self, command): |
1426 def pager(self, command: bytes) -> None: |
1414 """Start a pager for subsequent command output. |
1427 """Start a pager for subsequent command output. |
1415 |
1428 |
1416 Commands which produce a long stream of output should call |
1429 Commands which produce a long stream of output should call |
1417 this function to activate the user's preferred pagination |
1430 this function to activate the user's preferred pagination |
1418 mechanism (which may be no pager). Calling this function |
1431 mechanism (which may be no pager). Calling this function |
1489 # If the pager can't be spawned in dispatch when --pager=on is |
1502 # If the pager can't be spawned in dispatch when --pager=on is |
1490 # given, don't try again when the command runs, to avoid a duplicate |
1503 # given, don't try again when the command runs, to avoid a duplicate |
1491 # warning about a missing pager command. |
1504 # warning about a missing pager command. |
1492 self.disablepager() |
1505 self.disablepager() |
1493 |
1506 |
1494 def _runpager(self, command, env=None): |
1507 def _runpager(self, command: bytes, env=None) -> bool: |
1495 """Actually start the pager and set up file descriptors. |
1508 """Actually start the pager and set up file descriptors. |
1496 |
1509 |
1497 This is separate in part so that extensions (like chg) can |
1510 This is separate in part so that extensions (like chg) can |
1498 override how a pager is invoked. |
1511 override how a pager is invoked. |
1499 """ |
1512 """ |
1569 |
1582 |
1570 Handlers do not stay registered across request boundaries.""" |
1583 Handlers do not stay registered across request boundaries.""" |
1571 self._exithandlers.append((func, args, kwargs)) |
1584 self._exithandlers.append((func, args, kwargs)) |
1572 return func |
1585 return func |
1573 |
1586 |
1574 def interface(self, feature): |
1587 def interface(self, feature: bytes) -> bytes: |
1575 """what interface to use for interactive console features? |
1588 """what interface to use for interactive console features? |
1576 |
1589 |
1577 The interface is controlled by the value of `ui.interface` but also by |
1590 The interface is controlled by the value of `ui.interface` but also by |
1578 the value of feature-specific configuration. For example: |
1591 the value of feature-specific configuration. For example: |
1579 |
1592 |
1624 |
1637 |
1625 # Default interface for all the features |
1638 # Default interface for all the features |
1626 defaultinterface = b"text" |
1639 defaultinterface = b"text" |
1627 i = self.config(b"ui", b"interface") |
1640 i = self.config(b"ui", b"interface") |
1628 if i in alldefaults: |
1641 if i in alldefaults: |
1629 defaultinterface = i |
1642 defaultinterface = cast(bytes, i) # cast to help pytype |
1630 |
1643 |
1631 choseninterface = defaultinterface |
1644 choseninterface: bytes = defaultinterface |
1632 f = self.config(b"ui", b"interface.%s" % feature) |
1645 f = self.config(b"ui", b"interface.%s" % feature) |
1633 if f in availableinterfaces: |
1646 if f in availableinterfaces: |
1634 choseninterface = f |
1647 choseninterface = cast(bytes, f) # cast to help pytype |
1635 |
1648 |
1636 if i is not None and defaultinterface != i: |
1649 if i is not None and defaultinterface != i: |
1637 if f is not None: |
1650 if f is not None: |
1638 self.warn(_(b"invalid value for ui.interface: %s\n") % (i,)) |
1651 self.warn(_(b"invalid value for ui.interface: %s\n") % (i,)) |
1639 else: |
1652 else: |
1669 # usually those are non-interactive |
1682 # usually those are non-interactive |
1670 return self._isatty(self._fin) |
1683 return self._isatty(self._fin) |
1671 |
1684 |
1672 return i |
1685 return i |
1673 |
1686 |
1674 def termwidth(self): |
1687 def termwidth(self) -> int: |
1675 """how wide is the terminal in columns?""" |
1688 """how wide is the terminal in columns?""" |
1676 if b'COLUMNS' in encoding.environ: |
1689 if b'COLUMNS' in encoding.environ: |
1677 try: |
1690 try: |
1678 return int(encoding.environ[b'COLUMNS']) |
1691 return int(encoding.environ[b'COLUMNS']) |
1679 except ValueError: |
1692 except ValueError: |
1992 |
2005 |
1993 return t |
2006 return t |
1994 |
2007 |
1995 def system( |
2008 def system( |
1996 self, |
2009 self, |
1997 cmd, |
2010 cmd: bytes, |
1998 environ=None, |
2011 environ=None, |
1999 cwd=None, |
2012 cwd: Optional[bytes] = None, |
2000 onerr=None, |
2013 onerr: Optional[Callable[[bytes], Exception]] = None, |
2001 errprefix=None, |
2014 errprefix: Optional[bytes] = None, |
2002 blockedtag=None, |
2015 blockedtag: Optional[bytes] = None, |
2003 ): |
2016 ) -> int: |
2004 """execute shell command with appropriate output stream. command |
2017 """execute shell command with appropriate output stream. command |
2005 output will be redirected if fout is not stdout. |
2018 output will be redirected if fout is not stdout. |
2006 |
2019 |
2007 if command fails and onerr is None, return status, else raise onerr |
2020 if command fails and onerr is None, return status, else raise onerr |
2008 object as exception. |
2021 object as exception. |
2025 if errprefix: |
2038 if errprefix: |
2026 errmsg = b'%s: %s' % (errprefix, errmsg) |
2039 errmsg = b'%s: %s' % (errprefix, errmsg) |
2027 raise onerr(errmsg) |
2040 raise onerr(errmsg) |
2028 return rc |
2041 return rc |
2029 |
2042 |
2030 def _runsystem(self, cmd, environ, cwd, out): |
2043 def _runsystem(self, cmd: bytes, environ, cwd: Optional[bytes], out) -> int: |
2031 """actually execute the given shell command (can be overridden by |
2044 """actually execute the given shell command (can be overridden by |
2032 extensions like chg)""" |
2045 extensions like chg)""" |
2033 return procutil.system(cmd, environ=environ, cwd=cwd, out=out) |
2046 return procutil.system(cmd, environ=environ, cwd=cwd, out=out) |
2034 |
2047 |
2035 def traceback(self, exc=None, force=False): |
2048 def traceback(self, exc=None, force: bool = False): |
2036 """print exception traceback if traceback printing enabled or forced. |
2049 """print exception traceback if traceback printing enabled or forced. |
2037 only to call in exception handler. returns true if traceback |
2050 only to call in exception handler. returns true if traceback |
2038 printed.""" |
2051 printed.""" |
2039 if self.tracebackflag or force: |
2052 if self.tracebackflag or force: |
2040 if exc is None: |
2053 if exc is None: |
2128 |
2141 |
2129 def getlogger(self, name): |
2142 def getlogger(self, name): |
2130 """Returns a logger of the given name; or None if not registered""" |
2143 """Returns a logger of the given name; or None if not registered""" |
2131 return self._loggers.get(name) |
2144 return self._loggers.get(name) |
2132 |
2145 |
2133 def setlogger(self, name, logger): |
2146 def setlogger(self, name, logger) -> None: |
2134 """Install logger which can be identified later by the given name |
2147 """Install logger which can be identified later by the given name |
2135 |
2148 |
2136 More than one loggers can be registered. Use extension or module |
2149 More than one loggers can be registered. Use extension or module |
2137 name to uniquely identify the logger instance. |
2150 name to uniquely identify the logger instance. |
2138 """ |
2151 """ |
2139 self._loggers[name] = logger |
2152 self._loggers[name] = logger |
2140 |
2153 |
2141 def log(self, event, msgfmt, *msgargs, **opts): |
2154 def log(self, event, msgfmt, *msgargs, **opts) -> None: |
2142 """hook for logging facility extensions |
2155 """hook for logging facility extensions |
2143 |
2156 |
2144 event should be a readily-identifiable subsystem, which will |
2157 event should be a readily-identifiable subsystem, which will |
2145 allow filtering. |
2158 allow filtering. |
2146 |
2159 |
2237 hgweb. |
2250 hgweb. |
2238 """ |
2251 """ |
2239 return self._exportableenviron |
2252 return self._exportableenviron |
2240 |
2253 |
2241 @contextlib.contextmanager |
2254 @contextlib.contextmanager |
2242 def configoverride(self, overrides, source=b""): |
2255 def configoverride(self, overrides: _ConfigItems, source: bytes = b""): |
2243 """Context manager for temporary config overrides |
2256 """Context manager for temporary config overrides |
2244 `overrides` must be a dict of the following structure: |
2257 `overrides` must be a dict of the following structure: |
2245 {(section, name) : value}""" |
2258 {(section, name) : value}""" |
2246 backups = {} |
2259 backups = {} |
2247 try: |
2260 try: |
2255 # just restoring ui.quiet config to the previous value is not enough |
2268 # just restoring ui.quiet config to the previous value is not enough |
2256 # as it does not update ui.quiet class member |
2269 # as it does not update ui.quiet class member |
2257 if (b'ui', b'quiet') in overrides: |
2270 if (b'ui', b'quiet') in overrides: |
2258 self.fixconfig(section=b'ui') |
2271 self.fixconfig(section=b'ui') |
2259 |
2272 |
2260 def estimatememory(self): |
2273 def estimatememory(self) -> Optional[int]: |
2261 """Provide an estimate for the available system memory in Bytes. |
2274 """Provide an estimate for the available system memory in Bytes. |
2262 |
2275 |
2263 This can be overriden via ui.available-memory. It returns None, if |
2276 This can be overriden via ui.available-memory. It returns None, if |
2264 no estimate can be computed. |
2277 no estimate can be computed. |
2265 """ |
2278 """ |
2290 |
2303 |
2291 def haveprogbar() -> bool: |
2304 def haveprogbar() -> bool: |
2292 return _progresssingleton is not None |
2305 return _progresssingleton is not None |
2293 |
2306 |
2294 |
2307 |
2295 def _selectmsgdests(ui): |
2308 def _selectmsgdests(ui: ui): |
2296 name = ui.config(b'ui', b'message-output') |
2309 name = ui.config(b'ui', b'message-output') |
2297 if name == b'channel': |
2310 if name == b'channel': |
2298 if ui.fmsg: |
2311 if ui.fmsg: |
2299 return ui.fmsg, ui.fmsg |
2312 return ui.fmsg, ui.fmsg |
2300 else: |
2313 else: |