git-repo/pager.py

128 lines
3.1 KiB
Python
Raw Permalink Normal View History

# -*- coding:utf-8 -*-
2008-10-21 14:00:00 +00:00
#
# 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
2008-10-21 14:00:00 +00:00
import os
import select
import subprocess
2008-10-21 14:00:00 +00:00
import sys
import platform_utils
2008-10-21 14:00:00 +00:00
active = False
pager_process = None
old_stdout = None
old_stderr = None
2008-10-21 14:00:00 +00:00
2008-10-21 14:00:00 +00:00
def RunPager(globalConfig):
if not os.isatty(0) or not os.isatty(1):
2008-10-21 14:00:00 +00:00
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
2008-10-21 14:00:00 +00:00
# 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)
2008-10-21 14:00:00 +00:00
2008-10-21 14:00:00 +00:00
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'
2008-10-21 14:00:00 +00:00
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])
2008-10-21 14:00:00 +00:00
os.environ['LESS'] = 'FRSX'
try:
os.execvp(pager, [pager])
except OSError:
2008-10-21 14:00:00 +00:00
os.execv('/bin/sh', ['sh', '-c', pager])