Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit44c6d0b

Browse files
committed
Proc,#519: Rework error-exc msgs & log thread-pumps errors
+ No WindowsError exception.+ Add `test_exc.py` for unicode issues.+ Single-arg for decoding-streams in pump-func.
1 parentf11fdf1 commit44c6d0b

File tree

9 files changed

+240
-57
lines changed

9 files changed

+240
-57
lines changed

‎git/cmd.py‎

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
)
4646
importio
4747
from_ioimportUnsupportedOperation
48+
fromgit.excimportCommandError
4849

4950
execute_kwargs=set(('istream','with_keep_cwd','with_extended_output',
5051
'with_exceptions','as_process','stdout_as_string',
@@ -56,9 +57,6 @@
5657

5758
__all__= ('Git',)
5859

59-
ifis_win:
60-
WindowsError=OSError# @ReservedAssignment
61-
6260
ifPY3:
6361
_bchr=bchr
6462
else:
@@ -73,17 +71,23 @@ def _bchr(c):
7371
# Documentation
7472
## @{
7573

76-
defhandle_process_output(process,stdout_handler,stderr_handler,finalizer,
77-
decode_stdout=True,decode_stderr=True):
74+
defhandle_process_output(process,stdout_handler,stderr_handler,finalizer,decode_streams=True):
7875
"""Registers for notifications to lean that process output is ready to read, and dispatches lines to
7976
the respective line handlers. We are able to handle carriage returns in case progress is sent by that
8077
mean. For performance reasons, we only apply this to stderr.
8178
This function returns once the finalizer returns
79+
8280
:return: result of finalizer
8381
:param process: subprocess.Popen instance
8482
:param stdout_handler: f(stdout_line_string), or None
8583
:param stderr_hanlder: f(stderr_line_string), or None
86-
:param finalizer: f(proc) - wait for proc to finish"""
84+
:param finalizer: f(proc) - wait for proc to finish
85+
:param decode_streams:
86+
Assume stdout/stderr streams are binary and decode them vefore pushing\
87+
their contents to handlers.
88+
Set it to False if `universal_newline == True` (then streams are in text-mode)
89+
or if decoding must happen later (i.e. for Diffs).
90+
"""
8791

8892
def_parse_lines_from_buffer(buf):
8993
line=b''
@@ -156,18 +160,29 @@ def _deplete_buffer(fno, handler, buf_list, decode):
156160
# Oh ... probably we are on windows. or TC mockap provided for streams.
157161
# Anyhow, select.select() can only handle sockets, we have files
158162
# The only reliable way to do this now is to use threads and wait for both to finish
159-
def_handle_lines(fd,handler,decode):
160-
forlineinfd:
161-
ifhandler:
162-
ifdecode:
163-
line=line.decode(defenc)
164-
handler(line)
165-
163+
defpump_stream(cmdline,name,stream,is_decode,handler):
164+
try:
165+
forlineinstream:
166+
ifhandler:
167+
ifis_decode:
168+
line=line.decode(defenc)
169+
handler(line)
170+
exceptExceptionasex:
171+
log.error("Pumping %r of cmd(%s) failed due to: %r",name,cmdline,ex)
172+
raiseCommandError(['<%s-pump>'%name]+cmdline,ex)
173+
finally:
174+
stream.close()
175+
176+
cmdline=getattr(process,'args','')# PY3+ only
177+
ifnotisinstance(cmdline, (tuple,list)):
178+
cmdline=cmdline.split()
166179
threads= []
167-
forfd,handler,decodeinzip((process.stdout,process.stderr),
168-
(stdout_handler,stderr_handler),
169-
(decode_stdout,decode_stderr),):
170-
t=threading.Thread(target=_handle_lines,args=(fd,handler,decode))
180+
forname,stream,handlerin (
181+
('stdout',process.stdout,stdout_handler),
182+
('stderr',process.stderr,stderr_handler),
183+
):
184+
t=threading.Thread(target=pump_stream,
185+
args=(cmdline,name,stream,decode_streams,handler))
171186
t.setDaemon(True)
172187
t.start()
173188
threads.append(t)
@@ -177,8 +192,8 @@ def _handle_lines(fd, handler, decode):
177192
else:
178193
# poll is preferred, as select is limited to file handles up to 1024 ... . This could otherwise be
179194
# an issue for us, as it matters how many handles our own process has
180-
fdmap= {outfn: (stdout_handler, [b''],decode_stdout),
181-
errfn: (stderr_handler, [b''],decode_stderr)}
195+
fdmap= {outfn: (stdout_handler, [b''],decode_streams),
196+
errfn: (stderr_handler, [b''],decode_streams)}
182197

183198
READ_ONLY=select.POLLIN|select.POLLPRI|select.POLLHUP|select.POLLERR# @UndefinedVariable
184199
CLOSED=select.POLLHUP|select.POLLERR# @UndefinedVariable
@@ -334,7 +349,8 @@ def __del__(self):
334349
try:
335350
proc.terminate()
336351
proc.wait()# ensure process goes away
337-
except (OSError,WindowsError):
352+
exceptOSErrorasex:
353+
log.info("Ignored error after process has dies: %r",ex)
338354
pass# ignore error when process already died
339355
exceptAttributeError:
340356
# try windows
@@ -638,12 +654,12 @@ def execute(self, command,
638654
env.update(self._environment)
639655

640656
ifis_win:
641-
cmd_not_found_exception=WindowsError
657+
cmd_not_found_exception=OSError
642658
ifkill_after_timeout:
643-
raiseGitCommandError('"kill_after_timeout" feature is not supported on Windows.')
659+
raiseGitCommandError(command,'"kill_after_timeout" feature is not supported on Windows.')
644660
else:
645661
ifsys.version_info[0]>2:
646-
cmd_not_found_exception=FileNotFoundError# NOQA #this is defined, butflake8doesn't know
662+
cmd_not_found_exception=FileNotFoundError# NOQA #exists,flake8unknown @UndefinedVariable
647663
else:
648664
cmd_not_found_exception=OSError
649665
# end handle
@@ -663,7 +679,7 @@ def execute(self, command,
663679
**subprocess_kwargs
664680
)
665681
exceptcmd_not_found_exceptionaserr:
666-
raiseGitCommandNotFound('%s: %s'% (command[0],err))
682+
raiseGitCommandNotFound(command,err)
667683

668684
ifas_process:
669685
returnself.AutoInterrupt(proc,command)

‎git/diff.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ def _index_from_patch_format(cls, repo, proc):
407407

408408
## FIXME: Here SLURPING raw, need to re-phrase header-regexes linewise.
409409
text= []
410-
handle_process_output(proc,text.append,None,finalize_process,decode_stdout=False)
410+
handle_process_output(proc,text.append,None,finalize_process,decode_streams=False)
411411

412412
# for now, we have to bake the stream
413413
text=b''.join(text)
@@ -499,6 +499,6 @@ def handle_diff_line(line):
499499
new_file,deleted_file,rename_from,rename_to,'',change_type)
500500
index.append(diff)
501501

502-
handle_process_output(proc,handle_diff_line,None,finalize_process,decode_stdout=False)
502+
handle_process_output(proc,handle_diff_line,None,finalize_process,decode_streams=False)
503503

504504
returnindex

‎git/exc.py‎

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
""" Module containing all exceptions thrown througout the git package, """
77

88
fromgitdb.excimport*# NOQA
9-
fromgit.compatimportUnicodeMixin,safe_decode
9+
fromgit.compatimportUnicodeMixin,safe_decode,string_types
1010

1111

1212
classInvalidGitRepositoryError(Exception):
@@ -21,25 +21,56 @@ class NoSuchPathError(OSError):
2121
""" Thrown if a path could not be access by the system. """
2222

2323

24-
classGitCommandNotFound(Exception):
24+
classCommandError(UnicodeMixin,Exception):
25+
"""Base class for exceptions thrown at every stage of `Popen()` execution.
26+
27+
:param command:
28+
A non-empty list of argv comprising the command-line.
29+
"""
30+
31+
#: A unicode print-format with 2 `%s for `<cmdline>` and the rest,
32+
#: e.g.
33+
#: u"'%s' failed%s"
34+
_msg=u"Cmd('%s') failed%s"
35+
36+
def__init__(self,command,status=None,stderr=None,stdout=None):
37+
assertisinstance(command, (tuple,list)),command
38+
self.command=command
39+
self.status=status
40+
ifstatus:
41+
ifisinstance(status,Exception):
42+
status=u"%s('%s')"% (type(status).__name__,safe_decode(str(status)))
43+
else:
44+
try:
45+
status=u'exit code(%s)'%int(status)
46+
except:
47+
s=safe_decode(str(status))
48+
status=u"'%s'"%sifisinstance(status,string_types)elses
49+
50+
self._cmd=safe_decode(command[0])
51+
self._cmdline=u' '.join(safe_decode(i)foriincommand)
52+
self._cause=statusandu" due to: %s"%statusor"!"
53+
self.stdout=stdoutandu"\n stdout: '%s'"%safe_decode(stdout)or''
54+
self.stderr=stderrandu"\n stderr: '%s'"%safe_decode(stderr)or''
55+
56+
def__unicode__(self):
57+
return (self._msg+"\n cmdline: %s%s%s")% (
58+
self._cmd,self._cause,self._cmdline,self.stdout,self.stderr)
59+
60+
61+
classGitCommandNotFound(CommandError):
2562
"""Thrown if we cannot find the `git` executable in the PATH or at the path given by
2663
the GIT_PYTHON_GIT_EXECUTABLE environment variable"""
27-
pass
64+
def__init__(self,command,cause):
65+
super(GitCommandNotFound,self).__init__(command,cause)
66+
self._msg=u"Cmd('%s') not found%s"
2867

2968

30-
classGitCommandError(UnicodeMixin,Exception):
69+
classGitCommandError(CommandError):
3170
""" Thrown if execution of the git command fails with non-zero status code. """
3271

3372
def__init__(self,command,status,stderr=None,stdout=None):
34-
self.stderr=stderr
35-
self.stdout=stdout
36-
self.status=status
37-
self.command=command
38-
39-
def__unicode__(self):
40-
cmdline=u' '.join(safe_decode(i)foriinself.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)))
73+
super(GitCommandError,self).__init__(command,status,stderr,stdout)
4374

4475

4576
classCheckoutError(Exception):
@@ -76,20 +107,13 @@ class UnmergedEntriesError(CacheError):
76107
entries in the cache"""
77108

78109

79-
classHookExecutionError(UnicodeMixin,Exception):
110+
classHookExecutionError(CommandError):
80111
"""Thrown if a hook exits with a non-zero exit code. It provides access to the exit code and the string returned
81112
via standard output"""
82113

83-
def__init__(self,command,status,stdout=None,stderr=None):
84-
self.command=command
85-
self.status=status
86-
self.stdout=stdout
87-
self.stderr=stderr
88-
89-
def__unicode__(self):
90-
cmdline=u' '.join(safe_decode(i)foriinself.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)))
114+
def__init__(self,command,status,stderr=None,stdout=None):
115+
super(HookExecutionError,self).__init__(command,status,stderr,stdout)
116+
self._msg=u"Hook('%s') failed%s"
93117

94118

95119
classRepositoryDirtyError(Exception):

‎git/index/base.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,7 @@ def handle_stderr(proc, iter_checked_out_files):
10911091
kwargs['as_process']=True
10921092
kwargs['istream']=subprocess.PIPE
10931093
proc=self.repo.git.checkout_index(args,**kwargs)
1094+
# FIXME: Reading from GIL!
10941095
make_exc=lambda:GitCommandError(("git-checkout-index",)+tuple(args),128,proc.stderr.read())
10951096
checked_out_files=list()
10961097

‎git/remote.py‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,7 @@ def stdout_handler(line):
681681
# END for each line
682682

683683
try:
684-
handle_process_output(proc,stdout_handler,progress_handler,finalize_process,
685-
decode_stdout=False,decode_stderr=False)
684+
handle_process_output(proc,stdout_handler,progress_handler,finalize_process,decode_streams=False)
686685
exceptException:
687686
iflen(output)==0:
688687
raise

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2026 Movatter.jp