Support pager on Windows

Windows does not support pipe|fork, but we can simulate by creating
the pager as a child process, redirecting stdout/in/err appropriately
and then waiting for the child process to terminate after we are
done executing the repo command.

Change-Id: I5dd2bdeb4095e4d93bc678802e53c6d4eda0235b
This commit is contained in:
Renaud Paquay 2016-11-01 15:51:59 -07:00
parent 227ad2ef42
commit e8595e9df7
2 changed files with 38 additions and 3 deletions

View File

@ -55,7 +55,7 @@ from error import NoSuchProjectError
from error import RepoChangedException from error import RepoChangedException
import gitc_utils import gitc_utils
from manifest_xml import GitcManifest, XmlManifest from manifest_xml import GitcManifest, XmlManifest
from pager import RunPager from pager import RunPager, TerminatePager
from wrapper import WrapperPath, Wrapper from wrapper import WrapperPath, Wrapper
from subcmds import all_commands from subcmds import all_commands
@ -542,6 +542,7 @@ def _Main(argv):
print('fatal: %s' % e, file=sys.stderr) print('fatal: %s' % e, file=sys.stderr)
result = 128 result = 128
TerminatePager()
sys.exit(result) sys.exit(result)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -16,19 +16,53 @@
from __future__ import print_function from __future__ import print_function
import os import os
import select import select
import subprocess
import sys import sys
import platform_utils
active = False active = False
pager_process = None
old_stdout = None
old_stderr = None
def RunPager(globalConfig): def RunPager(globalConfig):
global active
if not os.isatty(0) or not os.isatty(1): if not os.isatty(0) or not os.isatty(1):
return return
pager = _SelectPager(globalConfig) pager = _SelectPager(globalConfig)
if pager == '' or pager == 'cat': if pager == '' or pager == 'cat':
return return
if platform_utils.isWindows():
_PipePager(pager);
else:
_ForkPager(pager)
def TerminatePager():
global pager_process, old_stdout, old_stderr
if pager_process:
sys.stdout.flush()
sys.stderr.flush()
pager_process.stdin.close()
pager_process.wait();
pager_process = None
# Restore initial stdout/err in case there is more output in this process
# after shutting down the pager process
sys.stdout = old_stdout
sys.stderr = old_stderr
def _PipePager(pager):
global pager_process, old_stdout, old_stderr
assert pager_process is None, "Only one active pager process at a time"
# Create pager process, piping stdout/err into its stdin
pager_process = subprocess.Popen([pager], stdin=subprocess.PIPE, stdout=sys.stdout, stderr=sys.stderr)
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = pager_process.stdin
sys.stderr = pager_process.stdin
def _ForkPager(pager):
global active
# This process turns into the pager; a child it forks will # This process turns into the pager; a child it forks will
# do the real processing and output back to the pager. This # do the real processing and output back to the pager. This
# is necessary to keep the pager in control of the tty. # is necessary to keep the pager in control of the tty.