3232# timeout by a factor of 10 if ASAN is enabled.
3333DEFAULT_TIMEOUT = 10 * (10 if ("ASAN_OPTIONS" in os .environ ) else 1 )
3434
35+ # See lldbtest.Base.spawnSubprocess, which should help ensure any processes
36+ # created by the DAP client are terminated correctly when the test ends.
37+ SpawnHelperCallback = Callable [[str , List [str ], List [str ]], subprocess .Popen ]
38+
3539## DAP type references
3640
3741
@@ -191,14 +195,16 @@ def __init__(
191195 self ,
192196 recv : BinaryIO ,
193197 send : BinaryIO ,
194- init_commands : list [str ],
195- log_file : Optional [TextIO ] = None ,
198+ init_commands : Optional [List [str ]] = None ,
199+ log_file : Optional [str ] = None ,
200+ spawn_helper : Optional [SpawnHelperCallback ] = None ,
196201 ):
197202 # For debugging test failures, try setting `trace_file = sys.stderr`.
198203 self .trace_file : Optional [TextIO ] = None
199204 self .log_file = log_file
200205 self .send = send
201206 self .recv = recv
207+ self .spawn_helper = spawn_helper
202208
203209 # Packets that have been received and processed but have not yet been
204210 # requested by a test case.
@@ -211,7 +217,7 @@ def __init__(
211217 self ._recv_thread = threading .Thread (target = self ._read_packet_thread )
212218
213219 # session state
214- self .init_commands = init_commands
220+ self .init_commands = init_commands if init_commands else []
215221 self .exit_status : Optional [int ] = None
216222 self .capabilities : Dict = {}
217223 self .initialized : bool = False
@@ -310,11 +316,6 @@ def collect_output(
310316 output += self .get_output (category , clear = clear )
311317 return output
312318
313- def _enqueue_recv_packet (self , packet : Optional [ProtocolMessage ]):
314- with self .recv_condition :
315- self .recv_packets .append (packet )
316- self .recv_condition .notify ()
317-
318319 def _handle_recv_packet (self , packet : Optional [ProtocolMessage ]) -> bool :
319320 """Handles an incoming packet.
320321
@@ -460,22 +461,11 @@ def _handle_reverse_request(self, request: Request) -> None:
460461 self .reverse_requests .append (request )
461462 arguments = request .get ("arguments" )
462463 if request ["command" ] == "runInTerminal" and arguments is not None :
463- in_shell = arguments .get ("argsCanBeInterpretedByShell" , False )
464- print ("spawning..." , arguments ["args" ])
465- proc = subprocess .Popen (
466- arguments ["args" ],
467- env = arguments .get ("env" , {}),
468- cwd = arguments .get ("cwd" , None ),
469- stdin = subprocess .DEVNULL ,
470- stdout = sys .stderr ,
471- stderr = sys .stderr ,
472- shell = in_shell ,
473- )
474- body = {}
475- if in_shell :
476- body ["shellProcessId" ] = proc .pid
477- else :
478- body ["processId" ] = proc .pid
464+ assert self .spawn_helper is not None , "Not configured to spawn subprocesses"
465+ [exe , * args ] = arguments ["args" ]
466+ env = [f"{ k } ={ v } " for k , v in arguments .get ("env" , {}).items ()]
467+ proc = self .spawn_helper (exe , args , env )
468+ body = {"processId" : proc .pid }
479469 self .send_packet (
480470 {
481471 "type" : "response" ,
@@ -1501,12 +1491,14 @@ def request_setInstructionBreakpoints(self, memory_reference=[]):
15011491class DebugAdapterServer (DebugCommunication ):
15021492 def __init__ (
15031493 self ,
1494+ * ,
15041495 executable : Optional [str ] = None ,
15051496 connection : Optional [str ] = None ,
1506- init_commands : list [str ] = [],
1507- log_file : Optional [TextIO ] = None ,
1508- env : Optional [dict [str , str ]] = None ,
1509- additional_args : list [str ] = [],
1497+ init_commands : Optional [list [str ]] = None ,
1498+ log_file : Optional [str ] = None ,
1499+ env : Optional [Dict [str , str ]] = None ,
1500+ additional_args : Optional [List [str ]] = None ,
1501+ spawn_helper : Optional [SpawnHelperCallback ] = None ,
15101502 ):
15111503 self .process = None
15121504 self .connection = None
@@ -1532,36 +1524,45 @@ def __init__(
15321524 s = socket .create_connection ((host .strip ("[]" ), int (port )))
15331525 else :
15341526 raise ValueError ("invalid connection: {}" .format (connection ))
1535- DebugCommunication .__init__ (
1536- self , s .makefile ("rb" ), s .makefile ("wb" ), init_commands , log_file
1527+ super ().__init__ (
1528+ s .makefile ("rb" ),
1529+ s .makefile ("wb" ),
1530+ init_commands ,
1531+ log_file ,
1532+ spawn_helper ,
15371533 )
15381534 self .connection = connection
15391535 else :
1540- DebugCommunication .__init__ (
1541- self , self .process .stdout , self .process .stdin , init_commands , log_file
1536+ super ().__init__ (
1537+ self .process .stdout ,
1538+ self .process .stdin ,
1539+ init_commands ,
1540+ log_file ,
1541+ spawn_helper ,
15421542 )
15431543
15441544 @classmethod
15451545 def launch (
15461546 cls ,
15471547 * ,
15481548 executable : str ,
1549- env : Optional [dict [str , str ]] = None ,
1550- log_file : Optional [TextIO ] = None ,
1549+ env : Optional [Dict [str , str ]] = None ,
1550+ log_file : Optional [str ] = None ,
15511551 connection : Optional [str ] = None ,
15521552 connection_timeout : Optional [int ] = None ,
1553- additional_args : list [ str ] = [] ,
1553+ additional_args : Optional [ List [ str ]] = None ,
15541554 ) -> tuple [subprocess .Popen , Optional [str ]]:
15551555 adapter_env = os .environ .copy ()
1556- if env is not None :
1556+ if env :
15571557 adapter_env .update (env )
15581558
15591559 if log_file :
15601560 adapter_env ["LLDBDAP_LOG" ] = log_file
15611561 args = [executable ]
15621562
15631563 # Add additional arguments first (like --no-lldbinit)
1564- args .extend (additional_args )
1564+ if additional_args :
1565+ args .extend (additional_args )
15651566
15661567 if connection is not None :
15671568 args .append ("--connection" )
0 commit comments