comparison hgext/pager.py @ 30876:3a4c0905f357

util: always force line buffered stdout when stdout is a tty (BC) pager replaced stdout with a line buffered version to work around glibc deciding on a buffering strategy on the first write to stdout. This is going to make my next patch hard, as replacing stdout will make tracking time spent blocked on it more challenging. Move the line buffering requirement to util.py, and remove it from pager. This means that the abuse of ui.formatted=True and pager set to cat or equivalent no longer results in a line-buffered output to a pipe, hence (BC), although I don't expect anyone to be affected
author Simon Farnsworth <simonfar@fb.com>
date Fri, 03 Feb 2017 15:10:27 -0800
parents aaa751585325
children 253d5c0f3a2f
comparison
equal deleted inserted replaced
30875:1791be8a95c5 30876:3a4c0905f357
85 def _runpager(ui, p): 85 def _runpager(ui, p):
86 pager = subprocess.Popen(p, shell=True, bufsize=-1, 86 pager = subprocess.Popen(p, shell=True, bufsize=-1,
87 close_fds=util.closefds, stdin=subprocess.PIPE, 87 close_fds=util.closefds, stdin=subprocess.PIPE,
88 stdout=util.stdout, stderr=util.stderr) 88 stdout=util.stdout, stderr=util.stderr)
89 89
90 # back up original file objects and descriptors 90 # back up original file descriptors
91 olduifout = ui.fout
92 oldstdout = util.stdout
93 stdoutfd = os.dup(util.stdout.fileno()) 91 stdoutfd = os.dup(util.stdout.fileno())
94 stderrfd = os.dup(util.stderr.fileno()) 92 stderrfd = os.dup(util.stderr.fileno())
95 93
96 # create new line-buffered stdout so that output can show up immediately
97 ui.fout = util.stdout = newstdout = os.fdopen(util.stdout.fileno(), 'wb', 1)
98 os.dup2(pager.stdin.fileno(), util.stdout.fileno()) 94 os.dup2(pager.stdin.fileno(), util.stdout.fileno())
99 if ui._isatty(util.stderr): 95 if ui._isatty(util.stderr):
100 os.dup2(pager.stdin.fileno(), util.stderr.fileno()) 96 os.dup2(pager.stdin.fileno(), util.stderr.fileno())
101 97
102 @atexit.register 98 @atexit.register
103 def killpager(): 99 def killpager():
104 if util.safehasattr(signal, "SIGINT"): 100 if util.safehasattr(signal, "SIGINT"):
105 signal.signal(signal.SIGINT, signal.SIG_IGN) 101 signal.signal(signal.SIGINT, signal.SIG_IGN)
106 pager.stdin.close() 102 # restore original fds, closing pager.stdin copies in the process
107 ui.fout = olduifout
108 util.stdout = oldstdout
109 # close new stdout while it's associated with pager; otherwise stdout
110 # fd would be closed when newstdout is deleted
111 newstdout.close()
112 # restore original fds: stdout is open again
113 os.dup2(stdoutfd, util.stdout.fileno()) 103 os.dup2(stdoutfd, util.stdout.fileno())
114 os.dup2(stderrfd, util.stderr.fileno()) 104 os.dup2(stderrfd, util.stderr.fileno())
105 pager.stdin.close()
115 pager.wait() 106 pager.wait()
116 107
117 def uisetup(ui): 108 def uisetup(ui):
118 class pagerui(ui.__class__): 109 class pagerui(ui.__class__):
119 def _runpager(self, pagercmd): 110 def _runpager(self, pagercmd):