# -*- coding:utf-8 -*- # # Copyright (C) 2008 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. 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): 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. # try: r, w = os.pipe() pid = os.fork() if not pid: os.dup2(w, 1) os.dup2(w, 2) os.close(r) os.close(w) active = True return os.dup2(r, 0) os.close(r) os.close(w) _BecomePager(pager) except Exception: print("fatal: cannot start pager '%s'" % pager, file=sys.stderr) sys.exit(255) def _SelectPager(globalConfig): try: return os.environ['GIT_PAGER'] except KeyError: pass pager = globalConfig.GetString('core.pager') if pager: return pager try: return os.environ['PAGER'] except KeyError: pass return 'less' def _BecomePager(pager): # Delaying execution of the pager until we have output # ready works around a long-standing bug in popularly # available versions of 'less', a better 'more'. # _a, _b, _c = select.select([0], [], [0]) os.environ['LESS'] = 'FRSX' try: os.execvp(pager, [pager]) except OSError: os.execv('/bin/sh', ['sh', '-c', pager])