blob: 7ad2577042d9887b891942c803429989e0087061 [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
62 pager_process = subprocess.Popen([pager], stdin=subprocess.PIPE, stdout=sys.stdout, stderr=sys.stderr)
63 old_stdout = sys.stdout
64 old_stderr = sys.stderr
65 sys.stdout = pager_process.stdin
66 sys.stderr = pager_process.stdin
67
David Pursehouse819827a2020-02-12 15:20:19 +090068
Renaud Paquaye8595e92016-11-01 15:51:59 -070069def _ForkPager(pager):
70 global active
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070071 # This process turns into the pager; a child it forks will
72 # do the real processing and output back to the pager. This
73 # is necessary to keep the pager in control of the tty.
74 #
75 try:
76 r, w = os.pipe()
77 pid = os.fork()
78 if not pid:
79 os.dup2(w, 1)
80 os.dup2(w, 2)
81 os.close(r)
82 os.close(w)
83 active = True
84 return
85
86 os.dup2(r, 0)
87 os.close(r)
88 os.close(w)
89
90 _BecomePager(pager)
91 except Exception:
Sarah Owenscecd1d82012-11-01 22:59:27 -070092 print("fatal: cannot start pager '%s'" % pager, file=sys.stderr)
David Pursehouse01f443d2012-10-03 19:11:28 +090093 sys.exit(255)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070094
David Pursehouse819827a2020-02-12 15:20:19 +090095
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070096def _SelectPager(globalConfig):
97 try:
98 return os.environ['GIT_PAGER']
99 except KeyError:
100 pass
101
102 pager = globalConfig.GetString('core.pager')
103 if pager:
104 return pager
105
106 try:
107 return os.environ['PAGER']
108 except KeyError:
109 pass
110
111 return 'less'
112
David Pursehouse819827a2020-02-12 15:20:19 +0900113
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700114def _BecomePager(pager):
115 # Delaying execution of the pager until we have output
116 # ready works around a long-standing bug in popularly
117 # available versions of 'less', a better 'more'.
118 #
David Pursehouse8a68ff92012-09-24 12:15:13 +0900119 _a, _b, _c = select.select([0], [], [0])
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700120
121 os.environ['LESS'] = 'FRSX'
122
123 try:
124 os.execvp(pager, [pager])
David Pursehouse8a68ff92012-09-24 12:15:13 +0900125 except OSError:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700126 os.execv('/bin/sh', ['sh', '-c', pager])