Always capture output for GitCommand

Switch the GitCommand program to always capture the output for stdout
and stderr.  And by default print the output while running.

The options capture_stdout and capture_stderr have effectively become
options to supress the printing of stdout and stderr.

Update the 'git fetch' to use '--progress' so that the progress messages
will be displayed.  git checks if the output location isatty() and if it
is not a TTY it will by default not print the progress messages.

Change-Id: Ifdae138e008f80a59195f9f43c911a1a5210ec60
This commit is contained in:
John L. Villalovos 2015-03-16 20:49:10 -07:00
parent 52b99aa91d
commit 9c76f67f13
2 changed files with 54 additions and 17 deletions

View File

@ -14,7 +14,9 @@
# limitations under the License. # limitations under the License.
from __future__ import print_function from __future__ import print_function
import fcntl
import os import os
import select
import sys import sys
import subprocess import subprocess
import tempfile import tempfile
@ -76,6 +78,16 @@ def terminate_ssh_clients():
_git_version = None _git_version = None
class _sfd(object):
"""select file descriptor class"""
def __init__(self, fd, dest, std_name):
assert std_name in ('stdout', 'stderr')
self.fd = fd
self.dest = dest
self.std_name = std_name
def fileno(self):
return self.fd.fileno()
class _GitCall(object): class _GitCall(object):
def version(self): def version(self):
p = GitCommand(None, ['--version'], capture_stdout=True) p = GitCommand(None, ['--version'], capture_stdout=True)
@ -139,6 +151,9 @@ class GitCommand(object):
if key in env: if key in env:
del env[key] del env[key]
# If we are not capturing std* then need to print it.
self.tee = {'stdout': not capture_stdout, 'stderr': not capture_stderr}
if disable_editor: if disable_editor:
_setenv(env, 'GIT_EDITOR', ':') _setenv(env, 'GIT_EDITOR', ':')
if ssh_proxy: if ssh_proxy:
@ -162,22 +177,21 @@ class GitCommand(object):
if gitdir: if gitdir:
_setenv(env, GIT_DIR, gitdir) _setenv(env, GIT_DIR, gitdir)
cwd = None cwd = None
command.extend(cmdv) command.append(cmdv[0])
# Need to use the --progress flag for fetch/clone so output will be
# displayed as by default git only does progress output if stderr is a TTY.
if sys.stderr.isatty() and cmdv[0] in ('fetch', 'clone'):
if '--progress' not in cmdv and '--quiet' not in cmdv:
command.append('--progress')
command.extend(cmdv[1:])
if provide_stdin: if provide_stdin:
stdin = subprocess.PIPE stdin = subprocess.PIPE
else: else:
stdin = None stdin = None
if capture_stdout: stdout = subprocess.PIPE
stdout = subprocess.PIPE stderr = subprocess.PIPE
else:
stdout = None
if capture_stderr:
stderr = subprocess.PIPE
else:
stderr = None
if IsTrace(): if IsTrace():
global LAST_CWD global LAST_CWD
@ -226,8 +240,34 @@ class GitCommand(object):
def Wait(self): def Wait(self):
try: try:
p = self.process p = self.process
(self.stdout, self.stderr) = p.communicate() rc = self._CaptureOutput()
rc = p.returncode
finally: finally:
_remove_ssh_client(p) _remove_ssh_client(p)
return rc return rc
def _CaptureOutput(self):
p = self.process
s_in = [_sfd(p.stdout, sys.stdout, 'stdout'),
_sfd(p.stderr, sys.stderr, 'stderr')]
self.stdout = ''
self.stderr = ''
for s in s_in:
flags = fcntl.fcntl(s.fd, fcntl.F_GETFL)
fcntl.fcntl(s.fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
while s_in:
in_ready, _, _ = select.select(s_in, [], [])
for s in in_ready:
buf = s.fd.read(4096)
if not buf:
s_in.remove(s)
continue
if s.std_name == 'stdout':
self.stdout += buf
else:
self.stderr += buf
if self.tee[s.std_name]:
s.dest.write(buf)
s.dest.flush()
return p.wait()

View File

@ -1874,10 +1874,8 @@ class Project(object):
ok = False ok = False
for _i in range(2): for _i in range(2):
gitcmd = GitCommand(self, cmd, bare=True, capture_stderr=True, gitcmd = GitCommand(self, cmd, bare=True, ssh_proxy=ssh_proxy)
ssh_proxy=ssh_proxy)
ret = gitcmd.Wait() ret = gitcmd.Wait()
print(gitcmd.stderr, file=sys.stderr, end='')
if ret == 0: if ret == 0:
ok = True ok = True
break break
@ -1886,9 +1884,8 @@ class Project(object):
"error:" in gitcmd.stderr and "error:" in gitcmd.stderr and
"git remote prune" in gitcmd.stderr): "git remote prune" in gitcmd.stderr):
prunecmd = GitCommand(self, ['remote', 'prune', name], bare=True, prunecmd = GitCommand(self, ['remote', 'prune', name], bare=True,
capture_stderr=True, ssh_proxy=ssh_proxy) ssh_proxy=ssh_proxy)
ret = prunecmd.Wait() ret = prunecmd.Wait()
print(prunecmd.stderr, file=sys.stderr, end='')
if ret: if ret:
break break
continue continue