4444 is_win ,
4545)
4646import io
47+ from _io import UnsupportedOperation
4748
4849execute_kwargs = set (('istream' , 'with_keep_cwd' , 'with_extended_output' ,
4950 'with_exceptions' , 'as_process' , 'stdout_as_string' ,
5657__all__ = ('Git' ,)
5758
5859if is_win :
59- WindowsError = OSError
60+ WindowsError = OSError # @ReservedAssignment
6061
6162if PY3 :
6263 _bchr = bchr
@@ -72,7 +73,8 @@ def _bchr(c):
7273# Documentation
7374## @{
7475
75- def handle_process_output (process , stdout_handler , stderr_handler , finalizer ):
76+ def handle_process_output (process , stdout_handler , stderr_handler , finalizer ,
77+ decode_stdout = True , decode_stderr = True ):
7678 """Registers for notifications to lean that process output is ready to read, and dispatches lines to
7779 the respective line handlers. We are able to handle carriage returns in case progress is sent by that
7880 mean. For performance reasons, we only apply this to stderr.
@@ -82,8 +84,6 @@ def handle_process_output(process, stdout_handler, stderr_handler, finalizer):
8284 :param stdout_handler: f(stdout_line_string), or None
8385 :param stderr_hanlder: f(stderr_line_string), or None
8486 :param finalizer: f(proc) - wait for proc to finish"""
85- fdmap = {process .stdout .fileno (): (stdout_handler , [b'' ]),
86- process .stderr .fileno (): (stderr_handler , [b'' ])}
8787
8888 def _parse_lines_from_buffer (buf ):
8989 line = b''
@@ -94,7 +94,7 @@ def _parse_lines_from_buffer(buf):
9494 bi += 1
9595
9696 if char in (b'\r ' , b'\n ' ) and line :
97- yield bi , line
97+ yield bi , line + b' \n '
9898 line = b''
9999 else :
100100 line += char
@@ -114,105 +114,111 @@ def _read_lines_from_fno(fno, last_buf_list):
114114 # keep remainder
115115 last_buf_list [0 ] = buf [bi :]
116116
117- def _dispatch_single_line (line , handler ):
118- line = line .decode (defenc )
117+ def _dispatch_single_line (line , handler , decode ):
118+ if decode :
119+ line = line .decode (defenc )
119120 if line and handler :
120121 handler (line )
121122 # end dispatch helper
122123 # end single line helper
123124
124- def _dispatch_lines (fno , handler , buf_list ):
125+ def _dispatch_lines (fno , handler , buf_list , decode ):
125126 lc = 0
126127 for line in _read_lines_from_fno (fno , buf_list ):
127- _dispatch_single_line (line , handler )
128+ _dispatch_single_line (line , handler , decode )
128129 lc += 1
129130 # for each line
130131 return lc
131132 # end
132133
133- def _deplete_buffer (fno , handler , buf_list , wg = None ):
134+ def _deplete_buffer (fno , handler , buf_list , decode ):
134135 lc = 0
135136 while True :
136- line_count = _dispatch_lines (fno , handler , buf_list )
137+ line_count = _dispatch_lines (fno , handler , buf_list , decode )
137138 lc += line_count
138139 if line_count == 0 :
139140 break
140141 # end deplete buffer
141142
142143 if buf_list [0 ]:
143- _dispatch_single_line (buf_list [0 ], handler )
144+ _dispatch_single_line (buf_list [0 ], handler , decode )
144145 lc += 1
145146 # end
146147
147- if wg :
148- wg .done ()
149-
150148 return lc
151149 # end
152150
153- if hasattr (select , 'poll' ):
154- # poll is preferred, as select is limited to file handles up to 1024 ... . This could otherwise be
155- # an issue for us, as it matters how many handles our own process has
156- poll = select .poll ()
157- READ_ONLY = select .POLLIN | select .POLLPRI | select .POLLHUP | select .POLLERR
158- CLOSED = select .POLLHUP | select .POLLERR
159-
160- poll .register (process .stdout , READ_ONLY )
161- poll .register (process .stderr , READ_ONLY )
162-
163- closed_streams = set ()
164- while True :
165- # no timeout
166-
167- try :
168- poll_result = poll .poll ()
169- except select .error as e :
170- if e .args [0 ] == errno .EINTR :
171- continue
172- raise
173- # end handle poll exception
174-
175- for fd , result in poll_result :
176- if result & CLOSED :
177- closed_streams .add (fd )
178- else :
179- _dispatch_lines (fd , * fdmap [fd ])
180- # end handle closed stream
181- # end for each poll-result tuple
182-
183- if len (closed_streams ) == len (fdmap ):
184- break
185- # end its all done
186- # end endless loop
187-
188- # Depelete all remaining buffers
189- for fno , (handler , buf_list ) in fdmap .items ():
190- _deplete_buffer (fno , handler , buf_list )
191- # end for each file handle
192-
193- for fno in fdmap .keys ():
194- poll .unregister (fno )
195- # end don't forget to unregister !
196- else :
197- # Oh ... probably we are on windows. select.select() can only handle sockets, we have files
151+ try :
152+ outfn = process .stdout .fileno ()
153+ errfn = process .stderr .fileno ()
154+ poll = select .poll () # @UndefinedVariable
155+ except (UnsupportedOperation , AttributeError ):
156+ # Oh ... probably we are on windows. or TC mockap provided for streams.
157+ # Anyhow, select.select() can only handle sockets, we have files
198158 # The only reliable way to do this now is to use threads and wait for both to finish
199- def _handle_lines (fd , handler ):
159+ def _handle_lines (fd , handler , decode ):
200160 for line in fd :
201- line = line .decode (defenc )
202- if line and handler :
161+ if handler :
162+ if decode :
163+ line = line .decode (defenc )
203164 handler (line )
204165
205166 threads = []
206- for fd , handler in zip ((process .stdout , process .stderr ),
207- (stdout_handler , stderr_handler )):
208- t = threading .Thread (target = _handle_lines , args = (fd , handler ))
167+ for fd , handler , decode in zip ((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 ))
209171 t .setDaemon (True )
210172 t .start ()
211173 threads .append (t )
212174
213175 for t in threads :
214176 t .join ()
215- # end
177+ else :
178+ # poll is preferred, as select is limited to file handles up to 1024 ... . This could otherwise be
179+ # 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 )}
182+
183+ READ_ONLY = select .POLLIN | select .POLLPRI | select .POLLHUP | select .POLLERR # @UndefinedVariable
184+ CLOSED = select .POLLHUP | select .POLLERR # @UndefinedVariable
185+
186+ poll .register (process .stdout , READ_ONLY )
187+ poll .register (process .stderr , READ_ONLY )
188+
189+ closed_streams = set ()
190+ while True :
191+ # no timeout
192+
193+ try :
194+ poll_result = poll .poll ()
195+ except select .error as e :
196+ if e .args [0 ] == errno .EINTR :
197+ continue
198+ raise
199+ # end handle poll exception
200+
201+ for fd , result in poll_result :
202+ if result & CLOSED :
203+ closed_streams .add (fd )
204+ else :
205+ _dispatch_lines (fd , * fdmap [fd ])
206+ # end handle closed stream
207+ # end for each poll-result tuple
208+
209+ if len (closed_streams ) == len (fdmap ):
210+ break
211+ # end its all done
212+ # end endless loop
213+
214+ # Depelete all remaining buffers
215+ for fno , (handler , buf_list , decode ) in fdmap .items ():
216+ _deplete_buffer (fno , handler , buf_list , decode )
217+ # end for each file handle
218+
219+ for fno in fdmap .keys ():
220+ poll .unregister (fno )
221+ # end don't forget to unregister !
216222
217223 return finalizer (process )
218224
@@ -458,6 +464,7 @@ def next(self):
458464 line = self .readline ()
459465 if not line :
460466 raise StopIteration
467+
461468 return line
462469
463470 def __del__ (self ):
0 commit comments