blob: 167f003f739d8e879a079e9da0b3a83059cc3f20 [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
David Pursehouse819827a2020-02-12 15:20:19 +090030
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070031def RunPager(globalConfig):
Shawn O. Pearce8f82a4f2009-04-01 07:24:22 -070032 if not os.isatty(0) or not os.isatty(1):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070033 return
34 pager = _SelectPager(globalConfig)
35 if pager == '' or pager == 'cat':
36 return
37
Renaud Paquaye8595e92016-11-01 15:51:59 -070038 if platform_utils.isWindows():
David Pursehouse03ae9922020-02-12 14:14:57 +090039 _PipePager(pager)
Renaud Paquaye8595e92016-11-01 15:51:59 -070040 else:
41 _ForkPager(pager)
42
David Pursehouse819827a2020-02-12 15:20:19 +090043
Renaud Paquaye8595e92016-11-01 15:51:59 -070044def TerminatePager():
45 global pager_process, old_stdout, old_stderr
46 if pager_process:
47 sys.stdout.flush()
48 sys.stderr.flush()
49 pager_process.stdin.close()
David Pursehouse03ae9922020-02-12 14:14:57 +090050 pager_process.wait()
Renaud Paquaye8595e92016-11-01 15:51:59 -070051 pager_process = None
52 # Restore initial stdout/err in case there is more output in this process
53 # after shutting down the pager process
54 sys.stdout = old_stdout
55 sys.stderr = old_stderr
56
David Pursehouse819827a2020-02-12 15:20:19 +090057
Renaud Paquaye8595e92016-11-01 15:51:59 -070058def _PipePager(pager):
59 global pager_process, old_stdout, old_stderr
60 assert pager_process is None, "Only one active pager process at a time"
61 # Create pager process, piping stdout/err into its stdin
David Pursehouse3cda50a2020-02-13 13:17:03 +090062 pager_process = subprocess.Popen([pager], stdin=subprocess.PIPE, stdout=sys.stdout,
63 stderr=sys.stderr)
Renaud Paquaye8595e92016-11-01 15:51:59 -070064 old_stdout = sys.stdout
65 old_stderr = sys.stderr
66 sys.stdout = pager_process.stdin
67 sys.stderr = pager_process.stdin
68
David Pursehouse819827a2020-02-12 15:20:19 +090069
Renaud Paquaye8595e92016-11-01 15:51:59 -070070def _ForkPager(pager):
71 global active
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070072 # This process turns into the pager; a child it forks will
73 # do the real processing and output back to the pager. This
74 # is necessary to keep the pager in control of the tty.
75 #
76 try:
77 r, w = os.pipe()
78 pid = os.fork()
79 if not pid:
80 os.dup2(w, 1)
81 os.dup2(w, 2)
82 os.close(r)
83 os.close(w)
84 active = True
85 return
86
87 os.dup2(r, 0)
88 os.close(r)
89 os.close(w)
90
91 _BecomePager(pager)
92 except Exception:
Sarah Owenscecd1d82012-11-01 22:59:27 -070093 print("fatal: cannot start pager '%s'" % pager, file=sys.stderr)
David Pursehouse01f443d2012-10-03 19:11:28 +090094 sys.exit(255)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070095
David Pursehouse819827a2020-02-12 15:20:19 +090096
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070097def _SelectPager(globalConfig):
98 try:
99 return os.environ['GIT_PAGER']
100 except KeyError:
101 pass
102
103 pager = globalConfig.GetString('core.pager')
104 if pager:
105 return pager
106
107 try:
108 return os.environ['PAGER']
109 except KeyError:
110 pass
111
112 return 'less'
113
David Pursehouse819827a2020-02-12 15:20:19 +0900114
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700115def _BecomePager(pager):
116 # Delaying execution of the pager until we have output
117 # ready works around a long-standing bug in popularly
118 # available versions of 'less', a better 'more'.
119 #
David Pursehouse8a68ff92012-09-24 12:15:13 +0900120 _a, _b, _c = select.select([0], [], [0])
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700121
122 os.environ['LESS'] = 'FRSX'
123
124 try:
125 os.execvp(pager, [pager])
David Pursehouse8a68ff92012-09-24 12:15:13 +0900126 except OSError:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700127 os.execv('/bin/sh', ['sh', '-c', pager])