summaryrefslogtreecommitdiffstats
path: root/git_command.py
diff options
context:
space:
mode:
Diffstat (limited to 'git_command.py')
-rw-r--r--git_command.py73
1 files changed, 59 insertions, 14 deletions
diff --git a/git_command.py b/git_command.py
index 354fc715..0893bff7 100644
--- a/git_command.py
+++ b/git_command.py
@@ -14,7 +14,9 @@
14# limitations under the License. 14# limitations under the License.
15 15
16from __future__ import print_function 16from __future__ import print_function
17import fcntl
17import os 18import os
19import select
18import sys 20import sys
19import subprocess 21import subprocess
20import tempfile 22import tempfile
@@ -76,17 +78,30 @@ def terminate_ssh_clients():
76 78
77_git_version = None 79_git_version = None
78 80
81class _sfd(object):
82 """select file descriptor class"""
83 def __init__(self, fd, dest, std_name):
84 assert std_name in ('stdout', 'stderr')
85 self.fd = fd
86 self.dest = dest
87 self.std_name = std_name
88 def fileno(self):
89 return self.fd.fileno()
90
79class _GitCall(object): 91class _GitCall(object):
80 def version(self): 92 def version(self):
81 p = GitCommand(None, ['--version'], capture_stdout=True) 93 p = GitCommand(None, ['--version'], capture_stdout=True)
82 if p.Wait() == 0: 94 if p.Wait() == 0:
83 return p.stdout 95 if hasattr(p.stdout, 'decode'):
96 return p.stdout.decode('utf-8')
97 else:
98 return p.stdout
84 return None 99 return None
85 100
86 def version_tuple(self): 101 def version_tuple(self):
87 global _git_version 102 global _git_version
88 if _git_version is None: 103 if _git_version is None:
89 ver_str = git.version().decode('utf-8') 104 ver_str = git.version()
90 _git_version = Wrapper().ParseGitVersion(ver_str) 105 _git_version = Wrapper().ParseGitVersion(ver_str)
91 if _git_version is None: 106 if _git_version is None:
92 print('fatal: "%s" unsupported' % ver_str, file=sys.stderr) 107 print('fatal: "%s" unsupported' % ver_str, file=sys.stderr)
@@ -139,6 +154,9 @@ class GitCommand(object):
139 if key in env: 154 if key in env:
140 del env[key] 155 del env[key]
141 156
157 # If we are not capturing std* then need to print it.
158 self.tee = {'stdout': not capture_stdout, 'stderr': not capture_stderr}
159
142 if disable_editor: 160 if disable_editor:
143 _setenv(env, 'GIT_EDITOR', ':') 161 _setenv(env, 'GIT_EDITOR', ':')
144 if ssh_proxy: 162 if ssh_proxy:
@@ -162,22 +180,21 @@ class GitCommand(object):
162 if gitdir: 180 if gitdir:
163 _setenv(env, GIT_DIR, gitdir) 181 _setenv(env, GIT_DIR, gitdir)
164 cwd = None 182 cwd = None
165 command.extend(cmdv) 183 command.append(cmdv[0])
184 # Need to use the --progress flag for fetch/clone so output will be
185 # displayed as by default git only does progress output if stderr is a TTY.
186 if sys.stderr.isatty() and cmdv[0] in ('fetch', 'clone'):
187 if '--progress' not in cmdv and '--quiet' not in cmdv:
188 command.append('--progress')
189 command.extend(cmdv[1:])
166 190
167 if provide_stdin: 191 if provide_stdin:
168 stdin = subprocess.PIPE 192 stdin = subprocess.PIPE
169 else: 193 else:
170 stdin = None 194 stdin = None
171 195
172 if capture_stdout: 196 stdout = subprocess.PIPE
173 stdout = subprocess.PIPE 197 stderr = subprocess.PIPE
174 else:
175 stdout = None
176
177 if capture_stderr:
178 stderr = subprocess.PIPE
179 else:
180 stderr = None
181 198
182 if IsTrace(): 199 if IsTrace():
183 global LAST_CWD 200 global LAST_CWD
@@ -226,8 +243,36 @@ class GitCommand(object):
226 def Wait(self): 243 def Wait(self):
227 try: 244 try:
228 p = self.process 245 p = self.process
229 (self.stdout, self.stderr) = p.communicate() 246 rc = self._CaptureOutput()
230 rc = p.returncode
231 finally: 247 finally:
232 _remove_ssh_client(p) 248 _remove_ssh_client(p)
233 return rc 249 return rc
250
251 def _CaptureOutput(self):
252 p = self.process
253 s_in = [_sfd(p.stdout, sys.stdout, 'stdout'),
254 _sfd(p.stderr, sys.stderr, 'stderr')]
255 self.stdout = ''
256 self.stderr = ''
257
258 for s in s_in:
259 flags = fcntl.fcntl(s.fd, fcntl.F_GETFL)
260 fcntl.fcntl(s.fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
261
262 while s_in:
263 in_ready, _, _ = select.select(s_in, [], [])
264 for s in in_ready:
265 buf = s.fd.read(4096)
266 if not buf:
267 s_in.remove(s)
268 continue
269 if not hasattr(buf, 'encode'):
270 buf = buf.decode()
271 if s.std_name == 'stdout':
272 self.stdout += buf
273 else:
274 self.stderr += buf
275 if self.tee[s.std_name]:
276 s.dest.write(buf)
277 s.dest.flush()
278 return p.wait()