comparison mercurial/ui.py @ 40593:7bffbbe03e90

ui: hide fin/fout/ferr attributes behind @property functions This allows keeping references to fout/ferr/fin which are updated when these properties are changed. See the next patch.
author Yuya Nishihara <yuya@tcha.org>
date Sat, 03 Nov 2018 20:53:31 +0900
parents d8997c5ce2ff
children 840cd57cde32
comparison
equal deleted inserted replaced
40592:d8997c5ce2ff 40593:7bffbbe03e90
229 self._terminfoparams = {} 229 self._terminfoparams = {}
230 self._styles = {} 230 self._styles = {}
231 self._uninterruptible = False 231 self._uninterruptible = False
232 232
233 if src: 233 if src:
234 self.fout = src.fout 234 self._fout = src._fout
235 self.ferr = src.ferr 235 self._ferr = src._ferr
236 self.fin = src.fin 236 self._fin = src._fin
237 self._finoutredirected = src._finoutredirected 237 self._finoutredirected = src._finoutredirected
238 self.pageractive = src.pageractive 238 self.pageractive = src.pageractive
239 self._disablepager = src._disablepager 239 self._disablepager = src._disablepager
240 self._tweaked = src._tweaked 240 self._tweaked = src._tweaked
241 241
254 self.fixconfig() 254 self.fixconfig()
255 255
256 self.httppasswordmgrdb = src.httppasswordmgrdb 256 self.httppasswordmgrdb = src.httppasswordmgrdb
257 self._blockedtimes = src._blockedtimes 257 self._blockedtimes = src._blockedtimes
258 else: 258 else:
259 self.fout = procutil.stdout 259 self._fout = procutil.stdout
260 self.ferr = procutil.stderr 260 self._ferr = procutil.stderr
261 self.fin = procutil.stdin 261 self._fin = procutil.stdin
262 self._finoutredirected = False 262 self._finoutredirected = False
263 self.pageractive = False 263 self.pageractive = False
264 self._disablepager = False 264 self._disablepager = False
265 self._tweaked = False 265 self._tweaked = False
266 266
882 882
883 @util.propertycache 883 @util.propertycache
884 def paths(self): 884 def paths(self):
885 return paths(self) 885 return paths(self)
886 886
887 @property
888 def fout(self):
889 return self._fout
890
891 @fout.setter
892 def fout(self, f):
893 self._fout = f
894
895 @property
896 def ferr(self):
897 return self._ferr
898
899 @ferr.setter
900 def ferr(self, f):
901 self._ferr = f
902
903 @property
904 def fin(self):
905 return self._fin
906
907 @fin.setter
908 def fin(self, f):
909 self._fin = f
910
887 def pushbuffer(self, error=False, subproc=False, labeled=False): 911 def pushbuffer(self, error=False, subproc=False, labeled=False):
888 """install a buffer to capture standard output of the ui object 912 """install a buffer to capture standard output of the ui object
889 913
890 If error is True, the error output will be captured too. 914 If error is True, the error output will be captured too.
891 915
912 self._bufferapplylabels = None 936 self._bufferapplylabels = None
913 937
914 return "".join(self._buffers.pop()) 938 return "".join(self._buffers.pop())
915 939
916 def _isbuffered(self, dest): 940 def _isbuffered(self, dest):
917 if dest is self.fout: 941 if dest is self._fout:
918 return bool(self._buffers) 942 return bool(self._buffers)
919 if dest is self.ferr: 943 if dest is self._ferr:
920 return bool(self._bufferstates and self._bufferstates[-1][0]) 944 return bool(self._bufferstates and self._bufferstates[-1][0])
921 return False 945 return False
922 946
923 def canwritewithoutlabels(self): 947 def canwritewithoutlabels(self):
924 '''check if write skips the label''' 948 '''check if write skips the label'''
945 969
946 When labeling output for a specific command, a label of 970 When labeling output for a specific command, a label of
947 "cmdname.type" is recommended. For example, status issues 971 "cmdname.type" is recommended. For example, status issues
948 a label of "status.modified" for modified files. 972 a label of "status.modified" for modified files.
949 ''' 973 '''
950 self._write(self.fout, *args, **opts) 974 self._write(self._fout, *args, **opts)
951 975
952 def write_err(self, *args, **opts): 976 def write_err(self, *args, **opts):
953 self._write(self.ferr, *args, **opts) 977 self._write(self._ferr, *args, **opts)
954 978
955 def _write(self, dest, *args, **opts): 979 def _write(self, dest, *args, **opts):
956 if self._isbuffered(dest): 980 if self._isbuffered(dest):
957 if self._bufferapplylabels: 981 if self._bufferapplylabels:
958 label = opts.get(r'label', '') 982 label = opts.get(r'label', '')
967 msg = b''.join(args) 991 msg = b''.join(args)
968 992
969 # opencode timeblockedsection because this is a critical path 993 # opencode timeblockedsection because this is a critical path
970 starttime = util.timer() 994 starttime = util.timer()
971 try: 995 try:
972 if dest is self.ferr and not getattr(self.fout, 'closed', False): 996 if dest is self._ferr and not getattr(self._fout, 'closed', False):
973 self.fout.flush() 997 self._fout.flush()
974 if self._colormode == 'win32': 998 if self._colormode == 'win32':
975 # windows color printing is its own can of crab, defer to 999 # windows color printing is its own can of crab, defer to
976 # the color module and that is it. 1000 # the color module and that is it.
977 color.win32print(self, dest.write, msg, **opts) 1001 color.win32print(self, dest.write, msg, **opts)
978 else: 1002 else:
980 label = opts.get(r'label', '') 1004 label = opts.get(r'label', '')
981 msg = self.label(msg, label) 1005 msg = self.label(msg, label)
982 dest.write(msg) 1006 dest.write(msg)
983 # stderr may be buffered under win32 when redirected to files, 1007 # stderr may be buffered under win32 when redirected to files,
984 # including stdout. 1008 # including stdout.
985 if dest is self.ferr and not getattr(self.ferr, 'closed', False): 1009 if dest is self._ferr and not getattr(self._ferr, 'closed', False):
986 dest.flush() 1010 dest.flush()
987 except IOError as err: 1011 except IOError as err:
988 if (dest is self.ferr 1012 if (dest is self._ferr
989 and err.errno in (errno.EPIPE, errno.EIO, errno.EBADF)): 1013 and err.errno in (errno.EPIPE, errno.EIO, errno.EBADF)):
990 # no way to report the error, so ignore it 1014 # no way to report the error, so ignore it
991 return 1015 return
992 raise error.StdioError(err) 1016 raise error.StdioError(err)
993 finally: 1017 finally:
997 def flush(self): 1021 def flush(self):
998 # opencode timeblockedsection because this is a critical path 1022 # opencode timeblockedsection because this is a critical path
999 starttime = util.timer() 1023 starttime = util.timer()
1000 try: 1024 try:
1001 try: 1025 try:
1002 self.fout.flush() 1026 self._fout.flush()
1003 except IOError as err: 1027 except IOError as err:
1004 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF): 1028 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1005 raise error.StdioError(err) 1029 raise error.StdioError(err)
1006 finally: 1030 finally:
1007 try: 1031 try:
1008 self.ferr.flush() 1032 self._ferr.flush()
1009 except IOError as err: 1033 except IOError as err:
1010 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF): 1034 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
1011 raise error.StdioError(err) 1035 raise error.StdioError(err)
1012 finally: 1036 finally:
1013 self._blockedtimes['stdio_blocked'] += \ 1037 self._blockedtimes['stdio_blocked'] += \
1253 ''' 1277 '''
1254 i = self.configbool("ui", "interactive") 1278 i = self.configbool("ui", "interactive")
1255 if i is None: 1279 if i is None:
1256 # some environments replace stdin without implementing isatty 1280 # some environments replace stdin without implementing isatty
1257 # usually those are non-interactive 1281 # usually those are non-interactive
1258 return self._isatty(self.fin) 1282 return self._isatty(self._fin)
1259 1283
1260 return i 1284 return i
1261 1285
1262 def termwidth(self): 1286 def termwidth(self):
1263 '''how wide is the terminal in columns? 1287 '''how wide is the terminal in columns?
1291 1315
1292 i = self.configbool("ui", "formatted") 1316 i = self.configbool("ui", "formatted")
1293 if i is None: 1317 if i is None:
1294 # some environments replace stdout without implementing isatty 1318 # some environments replace stdout without implementing isatty
1295 # usually those are non-interactive 1319 # usually those are non-interactive
1296 return self._isatty(self.fout) 1320 return self._isatty(self._fout)
1297 1321
1298 return i 1322 return i
1299 1323
1300 def _readline(self): 1324 def _readline(self):
1301 # Replacing stdin/stdout temporarily is a hard problem on Python 3 1325 # Replacing stdin/stdout temporarily is a hard problem on Python 3
1302 # because they have to be text streams with *no buffering*. Instead, 1326 # because they have to be text streams with *no buffering*. Instead,
1303 # we use rawinput() only if call_readline() will be invoked by 1327 # we use rawinput() only if call_readline() will be invoked by
1304 # PyOS_Readline(), so no I/O will be made at Python layer. 1328 # PyOS_Readline(), so no I/O will be made at Python layer.
1305 usereadline = (self._isatty(self.fin) and self._isatty(self.fout) 1329 usereadline = (self._isatty(self._fin) and self._isatty(self._fout)
1306 and procutil.isstdin(self.fin) 1330 and procutil.isstdin(self._fin)
1307 and procutil.isstdout(self.fout)) 1331 and procutil.isstdout(self._fout))
1308 if usereadline: 1332 if usereadline:
1309 try: 1333 try:
1310 # magically add command line editing support, where 1334 # magically add command line editing support, where
1311 # available 1335 # available
1312 import readline 1336 import readline
1324 # When stdin is in binary mode on Windows, it can cause 1348 # When stdin is in binary mode on Windows, it can cause
1325 # raw_input() to emit an extra trailing carriage return 1349 # raw_input() to emit an extra trailing carriage return
1326 if pycompat.oslinesep == b'\r\n' and line.endswith(b'\r'): 1350 if pycompat.oslinesep == b'\r\n' and line.endswith(b'\r'):
1327 line = line[:-1] 1351 line = line[:-1]
1328 else: 1352 else:
1329 self.fout.write(b' ') 1353 self._fout.write(b' ')
1330 self.fout.flush() 1354 self._fout.flush()
1331 line = self.fin.readline() 1355 line = self._fin.readline()
1332 if not line: 1356 if not line:
1333 raise EOFError 1357 raise EOFError
1334 line = line.rstrip(pycompat.oslinesep) 1358 line = line.rstrip(pycompat.oslinesep)
1335 1359
1336 return line 1360 return line
1341 """ 1365 """
1342 if not self.interactive(): 1366 if not self.interactive():
1343 self.write(msg, ' ', label='ui.prompt') 1367 self.write(msg, ' ', label='ui.prompt')
1344 self.write(default or '', "\n", label='ui.promptecho') 1368 self.write(default or '', "\n", label='ui.promptecho')
1345 return default 1369 return default
1346 self._writenobuf(self.fout, msg, label='ui.prompt') 1370 self._writenobuf(self._fout, msg, label='ui.prompt')
1347 self.flush() 1371 self.flush()
1348 try: 1372 try:
1349 r = self._readline() 1373 r = self._readline()
1350 if not r: 1374 if not r:
1351 r = default 1375 r = default
1409 self.write_err(self.label(prompt or _('password: '), 'ui.prompt')) 1433 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1410 # disable getpass() only if explicitly specified. it's still valid 1434 # disable getpass() only if explicitly specified. it's still valid
1411 # to interact with tty even if fin is not a tty. 1435 # to interact with tty even if fin is not a tty.
1412 with self.timeblockedsection('stdio'): 1436 with self.timeblockedsection('stdio'):
1413 if self.configbool('ui', 'nontty'): 1437 if self.configbool('ui', 'nontty'):
1414 l = self.fin.readline() 1438 l = self._fin.readline()
1415 if not l: 1439 if not l:
1416 raise EOFError 1440 raise EOFError
1417 return l.rstrip('\n') 1441 return l.rstrip('\n')
1418 else: 1442 else:
1419 return getpass.getpass('') 1443 return getpass.getpass('')
1535 if blockedtag is None: 1559 if blockedtag is None:
1536 # Long cmds tend to be because of an absolute path on cmd. Keep 1560 # Long cmds tend to be because of an absolute path on cmd. Keep
1537 # the tail end instead 1561 # the tail end instead
1538 cmdsuffix = cmd.translate(None, _keepalnum)[-85:] 1562 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1539 blockedtag = 'unknown_system_' + cmdsuffix 1563 blockedtag = 'unknown_system_' + cmdsuffix
1540 out = self.fout 1564 out = self._fout
1541 if any(s[1] for s in self._bufferstates): 1565 if any(s[1] for s in self._bufferstates):
1542 out = self 1566 out = self
1543 with self.timeblockedsection(blockedtag): 1567 with self.timeblockedsection(blockedtag):
1544 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out) 1568 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1545 if rc and onerr: 1569 if rc and onerr:
1680 if config is None or not self.configbool('devel', config): 1704 if config is None or not self.configbool('devel', config):
1681 return 1705 return
1682 msg = 'devel-warn: ' + msg 1706 msg = 'devel-warn: ' + msg
1683 stacklevel += 1 # get in develwarn 1707 stacklevel += 1 # get in develwarn
1684 if self.tracebackflag: 1708 if self.tracebackflag:
1685 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout) 1709 util.debugstacktrace(msg, stacklevel, self._ferr, self._fout)
1686 self.log('develwarn', '%s at:\n%s' % 1710 self.log('develwarn', '%s at:\n%s' %
1687 (msg, ''.join(util.getstackframes(stacklevel)))) 1711 (msg, ''.join(util.getstackframes(stacklevel))))
1688 else: 1712 else:
1689 curframe = inspect.currentframe() 1713 curframe = inspect.currentframe()
1690 calframe = inspect.getouterframes(curframe, 2) 1714 calframe = inspect.getouterframes(curframe, 2)