blob: 64090488d5b8dfda307bfa4d3809b22583c813bf [file] [log] [blame]
Mike Frysingerf6013762019-06-13 02:30:51 -04001# -*- coding:utf-8 -*-
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07002#
3# Copyright (C) 2008 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Sarah Owenscecd1d82012-11-01 22:59:27 -070017from __future__ import print_function
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070018import os
19import select
Renaud Paquaye8595e92016-11-01 15:51:59 -070020import subprocess
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070021import sys
22
Renaud Paquaye8595e92016-11-01 15:51:59 -070023import platform_utils
24
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070025active = False
Renaud Paquaye8595e92016-11-01 15:51:59 -070026pager_process = None
27old_stdout = None
28old_stderr = None
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070029
30def RunPager(globalConfig):
Shawn O. Pearce8f82a4f2009-04-01 07:24:22 -070031 if not os.isatty(0) or not os.isatty(1):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070032 return
33 pager = _SelectPager(globalConfig)
34 if pager == '' or pager == 'cat':
35 return
36
Renaud Paquaye8595e92016-11-01 15:51:59 -070037 if platform_utils.isWindows():
David Pursehouse03ae9922020-02-12 14:14:57 +090038 _PipePager(pager)
Renaud Paquaye8595e92016-11-01 15:51:59 -070039 else:
40 _ForkPager(pager)
41
42def TerminatePager():
43 global pager_process, old_stdout, old_stderr
44 if pager_process:
45 sys.stdout.flush()
46 sys.stderr.flush()
47 pager_process.stdin.close()
David Pursehouse03ae9922020-02-12 14:14:57 +090048 pager_process.wait()
Renaud Paquaye8595e92016-11-01 15:51:59 -070049 pager_process = None
50 # Restore initial stdout/err in case there is more output in this process
51 # after shutting down the pager process
52 sys.stdout = old_stdout
53 sys.stderr = old_stderr
54
55def _PipePager(pager):
56 global pager_process, old_stdout, old_stderr
57 assert pager_process is None, "Only one active pager process at a time"
58 # Create pager process, piping stdout/err into its stdin
59 pager_process = subprocess.Popen([pager], stdin=subprocess.PIPE, stdout=sys.stdout, stderr=sys.stderr)
60 old_stdout = sys.stdout
61 old_stderr = sys.stderr
62 sys.stdout = pager_process.stdin
63 sys.stderr = pager_process.stdin
64
65def _ForkPager(pager):
66 global active
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070067 # This process turns into the pager; a child it forks will
68 # do the real processing and output back to the pager. This
69 # is necessary to keep the pager in control of the tty.
70 #
71 try:
72 r, w = os.pipe()
73 pid = os.fork()
74 if not pid:
75 os.dup2(w, 1)
76 os.dup2(w, 2)
77 os.close(r)
78 os.close(w)
79 active = True
80 return
81
82 os.dup2(r, 0)
83 os.close(r)
84 os.close(w)
85
86 _BecomePager(pager)
87 except Exception:
Sarah Owenscecd1d82012-11-01 22:59:27 -070088 print("fatal: cannot start pager '%s'" % pager, file=sys.stderr)
David Pursehouse01f443d2012-10-03 19:11:28 +090089 sys.exit(255)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070090
91def _SelectPager(globalConfig):
92 try:
93 return os.environ['GIT_PAGER']
94 except KeyError:
95 pass
96
97 pager = globalConfig.GetString('core.pager')
98 if pager:
99 return pager
100
101 try:
102 return os.environ['PAGER']
103 except KeyError:
104 pass
105
106 return 'less'
107
108def _BecomePager(pager):
109 # Delaying execution of the pager until we have output
110 # ready works around a long-standing bug in popularly
111 # available versions of 'less', a better 'more'.
112 #
David Pursehouse8a68ff92012-09-24 12:15:13 +0900113 _a, _b, _c = select.select([0], [], [0])
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700114
115 os.environ['LESS'] = 'FRSX'
116
117 try:
118 os.execvp(pager, [pager])
David Pursehouse8a68ff92012-09-24 12:15:13 +0900119 except OSError:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700120 os.execv('/bin/sh', ['sh', '-c', pager])