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