diff options
Diffstat (limited to 'pager.py')
-rw-r--r-- | pager.py | 159 |
1 files changed, 79 insertions, 80 deletions
@@ -26,102 +26,101 @@ old_stderr = None | |||
26 | 26 | ||
27 | 27 | ||
28 | def RunPager(globalConfig): | 28 | def RunPager(globalConfig): |
29 | if not os.isatty(0) or not os.isatty(1): | 29 | if not os.isatty(0) or not os.isatty(1): |
30 | return | 30 | return |
31 | pager = _SelectPager(globalConfig) | 31 | pager = _SelectPager(globalConfig) |
32 | if pager == '' or pager == 'cat': | 32 | if pager == "" or pager == "cat": |
33 | return | 33 | return |
34 | 34 | ||
35 | if platform_utils.isWindows(): | 35 | if platform_utils.isWindows(): |
36 | _PipePager(pager) | 36 | _PipePager(pager) |
37 | else: | 37 | else: |
38 | _ForkPager(pager) | 38 | _ForkPager(pager) |
39 | 39 | ||
40 | 40 | ||
41 | def TerminatePager(): | 41 | def TerminatePager(): |
42 | global pager_process, old_stdout, old_stderr | 42 | global pager_process, old_stdout, old_stderr |
43 | if pager_process: | 43 | if pager_process: |
44 | sys.stdout.flush() | 44 | sys.stdout.flush() |
45 | sys.stderr.flush() | 45 | sys.stderr.flush() |
46 | pager_process.stdin.close() | 46 | pager_process.stdin.close() |
47 | pager_process.wait() | 47 | pager_process.wait() |
48 | pager_process = None | 48 | pager_process = None |
49 | # Restore initial stdout/err in case there is more output in this process | 49 | # Restore initial stdout/err in case there is more output in this |
50 | # after shutting down the pager process | 50 | # process after shutting down the pager process. |
51 | sys.stdout = old_stdout | 51 | sys.stdout = old_stdout |
52 | sys.stderr = old_stderr | 52 | sys.stderr = old_stderr |
53 | 53 | ||
54 | 54 | ||
55 | def _PipePager(pager): | 55 | def _PipePager(pager): |
56 | global pager_process, old_stdout, old_stderr | 56 | global pager_process, old_stdout, old_stderr |
57 | assert pager_process is None, "Only one active pager process at a time" | 57 | assert pager_process is None, "Only one active pager process at a time" |
58 | # Create pager process, piping stdout/err into its stdin | 58 | # Create pager process, piping stdout/err into its stdin. |
59 | try: | 59 | try: |
60 | pager_process = subprocess.Popen([pager], stdin=subprocess.PIPE, stdout=sys.stdout, | 60 | pager_process = subprocess.Popen( |
61 | stderr=sys.stderr) | 61 | [pager], stdin=subprocess.PIPE, stdout=sys.stdout, stderr=sys.stderr |
62 | except FileNotFoundError: | 62 | ) |
63 | sys.exit(f'fatal: cannot start pager "{pager}"') | 63 | except FileNotFoundError: |
64 | old_stdout = sys.stdout | 64 | sys.exit(f'fatal: cannot start pager "{pager}"') |
65 | old_stderr = sys.stderr | 65 | old_stdout = sys.stdout |
66 | sys.stdout = pager_process.stdin | 66 | old_stderr = sys.stderr |
67 | sys.stderr = pager_process.stdin | 67 | sys.stdout = pager_process.stdin |
68 | sys.stderr = pager_process.stdin | ||
68 | 69 | ||
69 | 70 | ||
70 | def _ForkPager(pager): | 71 | def _ForkPager(pager): |
71 | global active | 72 | global active |
72 | # This process turns into the pager; a child it forks will | 73 | # This process turns into the pager; a child it forks will |
73 | # do the real processing and output back to the pager. This | 74 | # do the real processing and output back to the pager. This |
74 | # is necessary to keep the pager in control of the tty. | 75 | # is necessary to keep the pager in control of the tty. |
75 | # | 76 | try: |
76 | try: | 77 | r, w = os.pipe() |
77 | r, w = os.pipe() | 78 | pid = os.fork() |
78 | pid = os.fork() | 79 | if not pid: |
79 | if not pid: | 80 | os.dup2(w, 1) |
80 | os.dup2(w, 1) | 81 | os.dup2(w, 2) |
81 | os.dup2(w, 2) | 82 | os.close(r) |
82 | os.close(r) | 83 | os.close(w) |
83 | os.close(w) | 84 | active = True |
84 | active = True | 85 | return |
85 | return | 86 | |
86 | 87 | os.dup2(r, 0) | |
87 | os.dup2(r, 0) | 88 | os.close(r) |
88 | os.close(r) | 89 | os.close(w) |
89 | os.close(w) | 90 | |
90 | 91 | _BecomePager(pager) | |
91 | _BecomePager(pager) | 92 | except Exception: |
92 | except Exception: | 93 | print("fatal: cannot start pager '%s'" % pager, file=sys.stderr) |
93 | print("fatal: cannot start pager '%s'" % pager, file=sys.stderr) | 94 | sys.exit(255) |
94 | sys.exit(255) | ||
95 | 95 | ||
96 | 96 | ||
97 | def _SelectPager(globalConfig): | 97 | def _SelectPager(globalConfig): |
98 | try: | 98 | try: |
99 | return os.environ['GIT_PAGER'] | 99 | return os.environ["GIT_PAGER"] |
100 | except KeyError: | 100 | except KeyError: |
101 | pass | 101 | pass |
102 | 102 | ||
103 | pager = globalConfig.GetString('core.pager') | 103 | pager = globalConfig.GetString("core.pager") |
104 | if pager: | 104 | if pager: |
105 | return pager | 105 | return pager |
106 | 106 | ||
107 | try: | 107 | try: |
108 | return os.environ['PAGER'] | 108 | return os.environ["PAGER"] |
109 | except KeyError: | 109 | except KeyError: |
110 | pass | 110 | pass |
111 | 111 | ||
112 | return 'less' | 112 | return "less" |
113 | 113 | ||
114 | 114 | ||
115 | def _BecomePager(pager): | 115 | def _BecomePager(pager): |
116 | # Delaying execution of the pager until we have output | 116 | # Delaying execution of the pager until we have output |
117 | # ready works around a long-standing bug in popularly | 117 | # ready works around a long-standing bug in popularly |
118 | # available versions of 'less', a better 'more'. | 118 | # available versions of 'less', a better 'more'. |
119 | # | 119 | _a, _b, _c = select.select([0], [], [0]) |
120 | _a, _b, _c = select.select([0], [], [0]) | 120 | |
121 | 121 | os.environ["LESS"] = "FRSX" | |
122 | os.environ['LESS'] = 'FRSX' | 122 | |
123 | 123 | try: | |
124 | try: | 124 | os.execvp(pager, [pager]) |
125 | os.execvp(pager, [pager]) | 125 | except OSError: |
126 | except OSError: | 126 | os.execv("/bin/sh", ["sh", "-c", pager]) |
127 | os.execv('/bin/sh', ['sh', '-c', pager]) | ||