From e8595e9df7980b0b7d9111de43d294c4439d474c Mon Sep 17 00:00:00 2001 From: Renaud Paquay Date: Tue, 1 Nov 2016 15:51:59 -0700 Subject: [PATCH] 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 --- main.py | 3 ++- pager.py | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 386b4f13..a6538c2a 100755 --- a/main.py +++ b/main.py @@ -55,7 +55,7 @@ from error import NoSuchProjectError from error import RepoChangedException import gitc_utils from manifest_xml import GitcManifest, XmlManifest -from pager import RunPager +from pager import RunPager, TerminatePager from wrapper import WrapperPath, Wrapper from subcmds import all_commands @@ -542,6 +542,7 @@ def _Main(argv): print('fatal: %s' % e, file=sys.stderr) result = 128 + TerminatePager() sys.exit(result) if __name__ == '__main__': diff --git a/pager.py b/pager.py index c6211419..0521c0c7 100755 --- a/pager.py +++ b/pager.py @@ -16,19 +16,53 @@ from __future__ import print_function import os import select +import subprocess import sys +import platform_utils + active = False +pager_process = None +old_stdout = None +old_stderr = None def RunPager(globalConfig): - global active - if not os.isatty(0) or not os.isatty(1): return pager = _SelectPager(globalConfig) if pager == '' or pager == 'cat': 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 # do the real processing and output back to the pager. This # is necessary to keep the pager in control of the tty.