10
10
import sys
11
11
from datetime import datetime
12
12
from datetime import timedelta
13
+ from functools import partial
13
14
from typing import cast
14
15
from typing import TYPE_CHECKING
15
16
@@ -131,21 +132,35 @@ def protocol_factory():
131
132
return Process (transport , protocol , loop , no_output_timeout_secs = no_output_timeout_secs )
132
133
133
134
135
+ def _handle_signal (proc , sig ):
136
+ if sig in proc ._handled_signals :
137
+ log .info (f"\n Caught { sig .name } again, killing the process ..." )
138
+ proc .kill ()
139
+ return
140
+ log .info (
141
+ f"\n Caught { sig .name } , terminating process ....\n Send { sig .name } again to kill the process."
142
+ )
143
+ proc ._handled_signals .append (sig )
144
+ proc .terminate ()
145
+
146
+
134
147
async def _subprocess_run (
135
- f ,
148
+ future ,
136
149
cmdline ,
137
150
check = True ,
138
151
no_output_timeout_secs : int | None = None ,
139
152
capture : bool = False ,
153
+ interactive : bool = False ,
140
154
):
141
155
stdout = subprocess .PIPE
142
156
stderr = subprocess .PIPE
143
157
kwargs = {}
144
- # Run in a separate program group
145
- if sys .platform .startswith ("win" ):
146
- kwargs ["creationflags" ] = subprocess .CREATE_NEW_PROCESS_GROUP
147
- else :
148
- kwargs ["preexec_fn" ] = os .setpgrp
158
+ if interactive is False :
159
+ # Run in a separate program group
160
+ if sys .platform .startswith ("win" ):
161
+ kwargs ["creationflags" ] = subprocess .CREATE_NEW_PROCESS_GROUP
162
+ else :
163
+ kwargs ["preexec_fn" ] = os .setpgrp
149
164
proc = await _create_subprocess_exec (
150
165
* cmdline ,
151
166
stdout = stdout ,
@@ -156,25 +171,27 @@ async def _subprocess_run(
156
171
capture = capture ,
157
172
** kwargs ,
158
173
)
174
+ proc ._handled_signals = []
159
175
loop = asyncio .get_running_loop ()
160
176
for signame in ("SIGINT" , "SIGTERM" ):
161
177
sig = getattr (signal , signame )
162
- loop .add_signal_handler (sig , proc . terminate )
178
+ loop .add_signal_handler (sig , partial ( _handle_signal , proc , sig ) )
163
179
stdout , stderr = await asyncio .shield (proc .communicate ())
164
180
result = subprocess .CompletedProcess (
165
181
args = cmdline ,
166
182
stdout = stdout ,
167
183
stderr = stderr ,
168
184
returncode = proc .returncode ,
169
185
)
170
- f .set_result (result )
186
+ future .set_result (result )
171
187
172
188
173
189
def run (
174
190
* cmdline ,
175
191
check = True ,
176
192
no_output_timeout_secs : int | None = None ,
177
193
capture : bool = False ,
194
+ interactive : bool = False ,
178
195
) -> subprocess .CompletedProcess [str ]:
179
196
"""
180
197
Run a command.
@@ -189,6 +206,7 @@ def run(
189
206
check ,
190
207
no_output_timeout_secs = no_output_timeout_secs ,
191
208
capture = capture ,
209
+ interactive = interactive ,
192
210
)
193
211
)
194
212
result = future .result ()
0 commit comments