33#
44# This module is part of GitPython and is released under
55# the BSD License: http://www.opensource.org/licenses/bsd-license.php
6-
6+ from __future__ import annotations
77from contextlib import contextmanager
88import io
99import logging
6868# Documentation
6969## @{
7070
71- def handle_process_output (process : Union [ subprocess . Popen , 'Git.AutoInterrupt' ] ,
71+ def handle_process_output (process : 'Git.AutoInterrupt' | Popen ,
7272 stdout_handler : Union [None ,
7373 Callable [[AnyStr ], None ],
7474 Callable [[List [AnyStr ]], None ],
@@ -78,7 +78,8 @@ def handle_process_output(process: Union[subprocess.Popen, 'Git.AutoInterrupt'],
7878 Callable [[List [AnyStr ]], None ]],
7979 finalizer : Union [None ,
8080 Callable [[Union [subprocess .Popen , 'Git.AutoInterrupt' ]], None ]] = None ,
81- decode_streams : bool = True ) -> None :
81+ decode_streams : bool = True ,
82+ timeout : float = 10.0 ) -> None :
8283 """Registers for notifications to learn that process output is ready to read, and dispatches lines to
8384 the respective line handlers.
8485 This function returns once the finalizer returns
@@ -93,9 +94,10 @@ def handle_process_output(process: Union[subprocess.Popen, 'Git.AutoInterrupt'],
9394 their contents to handlers.
9495 Set it to False if `universal_newline == True` (then streams are in text-mode)
9596 or if decoding must happen later (i.e. for Diffs).
97+ :param timeout: float, timeout to pass to t.join() in case it hangs. Default = 10.0 seconds
9698 """
9799 # Use 2 "pump" threads and wait for both to finish.
98- def pump_stream (cmdline : str , name : str , stream : Union [BinaryIO , TextIO ], is_decode : bool ,
100+ def pump_stream (cmdline : List [ str ] , name : str , stream : Union [BinaryIO , TextIO ], is_decode : bool ,
99101 handler : Union [None , Callable [[Union [bytes , str ]], None ]]) -> None :
100102 try :
101103 for line in stream :
@@ -107,22 +109,34 @@ def pump_stream(cmdline: str, name: str, stream: Union[BinaryIO, TextIO], is_dec
107109 else :
108110 handler (line )
109111 except Exception as ex :
110- log .error ("Pumping %r of cmd(%s) failed due to: %r" , name , remove_password_if_present ( cmdline ), ex )
111- raise CommandError (['<%s -pump>' % name ] + remove_password_if_present (cmdline ), ex ) from ex
112+ log .error (f "Pumping { name !r } of cmd({ remove_password_if_present ( cmdline ) } )} failed due to : { ex !r } " )
113+ raise CommandError ([f'< { name } -pump>' ] + remove_password_if_present (cmdline ), ex ) from ex
112114 finally :
113115 stream .close ()
114116
115- cmdline = getattr (process , 'args' , '' ) # PY3+ only
117+
118+
119+ if hasattr (process , 'proc' ):
120+ process = cast ('Git.AutoInterrupt' , process )
121+ cmdline : str | Tuple [str , ...] | List [str ] = getattr (process .proc , 'args' , '' )
122+ p_stdout = process .proc .stdout
123+ p_stderr = process .proc .stderr
124+ else :
125+ process = cast (Popen , process )
126+ cmdline = getattr (process , 'args' , '' )
127+ p_stdout = process .stdout
128+ p_stderr = process .stderr
129+
116130 if not isinstance (cmdline , (tuple , list )):
117131 cmdline = cmdline .split ()
118132
119- pumps = []
120- if process . stdout :
121- pumps .append (('stdout' , process . stdout , stdout_handler ))
122- if process . stderr :
123- pumps .append (('stderr' , process . stderr , stderr_handler ))
133+ pumps : List [ Tuple [ str , IO , Callable [..., None ] | None ]] = []
134+ if p_stdout :
135+ pumps .append (('stdout' , p_stdout , stdout_handler ))
136+ if p_stderr :
137+ pumps .append (('stderr' , p_stderr , stderr_handler ))
124138
125- threads = []
139+ threads : List [ threading . Thread ] = []
126140
127141 for name , stream , handler in pumps :
128142 t = threading .Thread (target = pump_stream ,
@@ -134,7 +148,7 @@ def pump_stream(cmdline: str, name: str, stream: Union[BinaryIO, TextIO], is_dec
134148 ## FIXME: Why Join?? Will block if `stdin` needs feeding...
135149 #
136150 for t in threads :
137- t .join ()
151+ t .join (timeout = timeout )
138152
139153 if finalizer :
140154 return finalizer (process )
0 commit comments