diff options
| -rw-r--r-- | git_command.py | 64 | ||||
| -rw-r--r-- | project.py | 7 |
2 files changed, 54 insertions, 17 deletions
diff --git a/git_command.py b/git_command.py index 53b3e75c..259fb02c 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 | ||
| 16 | from __future__ import print_function | 16 | from __future__ import print_function |
| 17 | import fcntl | ||
| 17 | import os | 18 | import os |
| 19 | import select | ||
| 18 | import sys | 20 | import sys |
| 19 | import subprocess | 21 | import subprocess |
| 20 | import tempfile | 22 | import tempfile |
| @@ -76,6 +78,16 @@ def terminate_ssh_clients(): | |||
| 76 | 78 | ||
| 77 | _git_version = None | 79 | _git_version = None |
| 78 | 80 | ||
| 81 | class _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 | |||
| 79 | class _GitCall(object): | 91 | class _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) |
| @@ -139,6 +151,9 @@ class GitCommand(object): | |||
| 139 | if key in env: | 151 | if key in env: |
| 140 | del env[key] | 152 | del env[key] |
| 141 | 153 | ||
| 154 | # If we are not capturing std* then need to print it. | ||
| 155 | self.tee = {'stdout': not capture_stdout, 'stderr': not capture_stderr} | ||
| 156 | |||
| 142 | if disable_editor: | 157 | if disable_editor: |
| 143 | _setenv(env, 'GIT_EDITOR', ':') | 158 | _setenv(env, 'GIT_EDITOR', ':') |
| 144 | if ssh_proxy: | 159 | if ssh_proxy: |
| @@ -162,22 +177,21 @@ class GitCommand(object): | |||
| 162 | if gitdir: | 177 | if gitdir: |
| 163 | _setenv(env, GIT_DIR, gitdir) | 178 | _setenv(env, GIT_DIR, gitdir) |
| 164 | cwd = None | 179 | cwd = None |
| 165 | command.extend(cmdv) | 180 | command.append(cmdv[0]) |
| 181 | # Need to use the --progress flag for fetch/clone so output will be | ||
| 182 | # displayed as by default git only does progress output if stderr is a TTY. | ||
| 183 | if sys.stderr.isatty() and cmdv[0] in ('fetch', 'clone'): | ||
| 184 | if '--progress' not in cmdv and '--quiet' not in cmdv: | ||
| 185 | command.append('--progress') | ||
| 186 | command.extend(cmdv[1:]) | ||
| 166 | 187 | ||
| 167 | if provide_stdin: | 188 | if provide_stdin: |
| 168 | stdin = subprocess.PIPE | 189 | stdin = subprocess.PIPE |
| 169 | else: | 190 | else: |
| 170 | stdin = None | 191 | stdin = None |
| 171 | 192 | ||
| 172 | if capture_stdout: | 193 | stdout = subprocess.PIPE |
| 173 | stdout = subprocess.PIPE | 194 | stderr = subprocess.PIPE |
| 174 | else: | ||
| 175 | stdout = None | ||
| 176 | |||
| 177 | if capture_stderr: | ||
| 178 | stderr = subprocess.PIPE | ||
| 179 | else: | ||
| 180 | stderr = None | ||
| 181 | 195 | ||
| 182 | if IsTrace(): | 196 | if IsTrace(): |
| 183 | global LAST_CWD | 197 | global LAST_CWD |
| @@ -226,8 +240,34 @@ class GitCommand(object): | |||
| 226 | def Wait(self): | 240 | def Wait(self): |
| 227 | try: | 241 | try: |
| 228 | p = self.process | 242 | p = self.process |
| 229 | (self.stdout, self.stderr) = p.communicate() | 243 | rc = self._CaptureOutput() |
| 230 | rc = p.returncode | ||
| 231 | finally: | 244 | finally: |
| 232 | _remove_ssh_client(p) | 245 | _remove_ssh_client(p) |
| 233 | return rc | 246 | return rc |
| 247 | |||
| 248 | def _CaptureOutput(self): | ||
| 249 | p = self.process | ||
| 250 | s_in = [_sfd(p.stdout, sys.stdout, 'stdout'), | ||
| 251 | _sfd(p.stderr, sys.stderr, 'stderr')] | ||
| 252 | self.stdout = '' | ||
| 253 | self.stderr = '' | ||
| 254 | |||
| 255 | for s in s_in: | ||
| 256 | flags = fcntl.fcntl(s.fd, fcntl.F_GETFL) | ||
| 257 | fcntl.fcntl(s.fd, fcntl.F_SETFL, flags | os.O_NONBLOCK) | ||
| 258 | |||
| 259 | while s_in: | ||
| 260 | in_ready, _, _ = select.select(s_in, [], []) | ||
| 261 | for s in in_ready: | ||
| 262 | buf = s.fd.read(4096) | ||
| 263 | if not buf: | ||
| 264 | s_in.remove(s) | ||
| 265 | continue | ||
| 266 | if s.std_name == 'stdout': | ||
| 267 | self.stdout += buf | ||
| 268 | else: | ||
| 269 | self.stderr += buf | ||
| 270 | if self.tee[s.std_name]: | ||
| 271 | s.dest.write(buf) | ||
| 272 | s.dest.flush() | ||
| 273 | return p.wait() | ||
| @@ -1874,10 +1874,8 @@ class Project(object): | |||
| 1874 | 1874 | ||
| 1875 | ok = False | 1875 | ok = False |
| 1876 | for _i in range(2): | 1876 | for _i in range(2): |
| 1877 | gitcmd = GitCommand(self, cmd, bare=True, capture_stderr=True, | 1877 | gitcmd = GitCommand(self, cmd, bare=True, ssh_proxy=ssh_proxy) |
| 1878 | ssh_proxy=ssh_proxy) | ||
| 1879 | ret = gitcmd.Wait() | 1878 | ret = gitcmd.Wait() |
| 1880 | print(gitcmd.stderr, file=sys.stderr, end='') | ||
| 1881 | if ret == 0: | 1879 | if ret == 0: |
| 1882 | ok = True | 1880 | ok = True |
| 1883 | break | 1881 | break |
| @@ -1886,9 +1884,8 @@ class Project(object): | |||
| 1886 | "error:" in gitcmd.stderr and | 1884 | "error:" in gitcmd.stderr and |
| 1887 | "git remote prune" in gitcmd.stderr): | 1885 | "git remote prune" in gitcmd.stderr): |
| 1888 | prunecmd = GitCommand(self, ['remote', 'prune', name], bare=True, | 1886 | prunecmd = GitCommand(self, ['remote', 'prune', name], bare=True, |
| 1889 | capture_stderr=True, ssh_proxy=ssh_proxy) | 1887 | ssh_proxy=ssh_proxy) |
| 1890 | ret = prunecmd.Wait() | 1888 | ret = prunecmd.Wait() |
| 1891 | print(prunecmd.stderr, file=sys.stderr, end='') | ||
| 1892 | if ret: | 1889 | if ret: |
| 1893 | break | 1890 | break |
| 1894 | continue | 1891 | continue |
