Skip to content

Commit cf2335a

Browse files
committed
Win, hook, #519: Consume Hook Popen-proc out of GIL
+ HookException thrown on Popen, and were missed on Windows. + No SHELL on Popen?? + Minor fixes: + Try harder to delete trees - no remorses. + Simplify exception reprs. + Unittest-ize test_index assertions.
1 parent a5db3d3 commit cf2335a

File tree

5 files changed

+124
-108
lines changed

5 files changed

+124
-108
lines changed

‎git/compat.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ def safe_decode(s):
6262
return s
6363
elif isinstance(s, bytes):
6464
return s.decode(defenc, 'replace')
65-
raise TypeError('Expected bytes or text, but got %r' % (s,))
65+
elif s is not None:
66+
raise TypeError('Expected bytes or text, but got %r' % (s,))
6667

6768

6869
def with_metaclass(meta, *bases):

‎git/exc.py

+9-12
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,9 @@ def __init__(self, command, status, stderr=None, stdout=None):
3737
self.command = command
3838

3939
def __unicode__(self):
40-
ret = u"'%s' returned with exit code %s" % \
41-
(u' '.join(safe_decode(i) for i in self.command), self.status)
42-
if self.stderr:
43-
ret += u"\nstderr: '%s'" % safe_decode(self.stderr)
44-
if self.stdout:
45-
ret += u"\nstdout: '%s'" % safe_decode(self.stdout)
46-
return ret
40+
cmdline = u' '.join(safe_decode(i) for i in self.command)
41+
return (u"'%s' returned with exit code %s\n stdout: '%s'\n stderr: '%s'"
42+
% (cmdline, self.status, safe_decode(self.stdout), safe_decode(self.stderr)))
4743

4844

4945
class CheckoutError(Exception):
@@ -80,19 +76,20 @@ class UnmergedEntriesError(CacheError):
8076
entries in the cache"""
8177

8278

83-
class HookExecutionError(Exception):
79+
class HookExecutionError(UnicodeMixin, Exception):
8480
"""Thrown if a hook exits with a non-zero exit code. It provides access to the exit code and the string returned
8581
via standard output"""
8682

87-
def __init__(self, command, status, stdout, stderr):
83+
def __init__(self, command, status, stdout=None, stderr=None):
8884
self.command = command
8985
self.status = status
9086
self.stdout = stdout
9187
self.stderr = stderr
9288

93-
def __str__(self):
94-
return ("'%s' hook returned with exit code %i\nstdout: '%s'\nstderr: '%s'"
95-
% (self.command, self.status, self.stdout, self.stderr))
89+
def __unicode__(self):
90+
cmdline = u' '.join(safe_decode(i) for i in self.command)
91+
return (u"'%s' hook failed with %r\n stdout: '%s'\n stderr: '%s'"
92+
% (cmdline, self.status, safe_decode(self.stdout), safe_decode(self.stderr)))
9693

9794

9895
class RepositoryDirtyError(Exception):

‎git/index/fun.py

+22-17
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
import os
1515
import subprocess
1616

17-
from git.util import IndexFileSHA1Writer
18-
from git.cmd import PROC_CREATIONFLAGS
17+
from git.util import IndexFileSHA1Writer, finalize_process
18+
from git.cmd import PROC_CREATIONFLAGS, handle_process_output
1919
from git.exc import (
2020
UnmergedEntriesError,
2121
HookExecutionError
@@ -71,21 +71,26 @@ def run_commit_hook(name, index):
7171
env = os.environ.copy()
7272
env['GIT_INDEX_FILE'] = index.path
7373
env['GIT_EDITOR'] = ':'
74-
cmd = subprocess.Popen(hp,
75-
env=env,
76-
stdout=subprocess.PIPE,
77-
stderr=subprocess.PIPE,
78-
cwd=index.repo.working_dir,
79-
close_fds=is_posix,
80-
creationflags=PROC_CREATIONFLAGS,)
81-
stdout, stderr = cmd.communicate()
82-
cmd.stdout.close()
83-
cmd.stderr.close()
84-
85-
if cmd.returncode != 0:
86-
stdout = force_text(stdout, defenc)
87-
stderr = force_text(stderr, defenc)
88-
raise HookExecutionError(hp, cmd.returncode, stdout, stderr)
74+
try:
75+
cmd = subprocess.Popen(hp,
76+
env=env,
77+
stdout=subprocess.PIPE,
78+
stderr=subprocess.PIPE,
79+
cwd=index.repo.working_dir,
80+
close_fds=is_posix,
81+
creationflags=PROC_CREATIONFLAGS,)
82+
except Exception as ex:
83+
raise HookExecutionError(hp, ex)
84+
else:
85+
stdout = []
86+
stderr = []
87+
handle_process_output(cmd, stdout.append, stderr.append, finalize_process)
88+
stdout = ''.join(stdout)
89+
stderr = ''.join(stderr)
90+
if cmd.returncode != 0:
91+
stdout = force_text(stdout, defenc)
92+
stderr = force_text(stderr, defenc)
93+
raise HookExecutionError(hp, cmd.returncode, stdout, stderr)
8994
# end handle return code
9095

9196

0 commit comments

Comments
 (0)