@@ -92,6 +92,7 @@ def executable(self):
9292
9393 tool.log = MyLogger()
9494 """
95+
9596 shell : bool = False
9697
9798 def __init__ (self , namespace , args = []):
@@ -209,34 +210,30 @@ def executable(self):
209210
210211
211212class CmdWrapper (CommandWrapper ):
212- """Wrapper class for running wrapped commands in command prompt ."""
213+ """Wrapper class for running wrapped commands in Windows cmd.exe ."""
213214
214215 def __init__ (self , namespace = config .DEFAULT_NAMESPACE , args = []):
215- """
216- Initializes the command wrapper with the given namespace and args,
217- replacing the original command with the shell command, e.g.:
218-
219- >>> cmd = CmdWrapper(stack, ['dir'])
220- >>> print(cmd.executable())
221- cmd
222- >>> print(cmd.args)
223- ['/c', 'dir']
216+ super ().__init__ (namespace , args )
224217
225- :param namespace: environment stack name (default: 'default').
226- :param args: command and arguments as a list.
227- """
228- super (CmdWrapper , self ).__init__ (namespace , args )
229- self .args = ["/c" , self .cmd ]
218+ # Always run through cmd.exe explicitly
230219 self .shell = False
220+ self ._cmd_exe = config .SHELL # expected: "cmd" or "cmd.exe"
231221
232- def get_subprocess_args (self , cmd ):
233- """Returns the arguments to be passed to the subprocess."""
234- return [cmd ] + self .args
222+ # Join the intended argv into one command-line string for /c
223+ cmdline = shell_join (self .cmd )
224+
225+ # cmd.exe /c <command>
226+ self ._subprocess_argv = [self ._cmd_exe , "/c" , cmdline ]
235227
236228 def executable (self ):
237- """Returns the shell command to run the original command."""
238- self .cmd = config .SHELL
239- return self .cmd
229+ return self ._cmd_exe
230+
231+ def get_subprocess_args (self , cmd ):
232+ # Not used (we override get_subprocess_command)
233+ return []
234+
235+ def get_subprocess_command (self , env ):
236+ return list (self ._subprocess_argv )
240237
241238
242239def run_command (command : str , namespace : str = config .DEFAULT_NAMESPACE ):
@@ -254,39 +251,23 @@ def run_command(command: str, namespace: str = config.DEFAULT_NAMESPACE):
254251
255252 :param command: command to run as a list of arguments.
256253 :param namespace: environment stack name (default: 'default').
257- :param interactive: run the command in an interactive shell (default: True).
258254 :returns: command exit code
259255 """
260256 logger .setup_stream_handler ()
261- shellname = os .path .basename (config .SHELL )
262-
263- # normalize to argv list
257+ shellname = os .path .basename (config .SHELL ).lower ()
264258 argv = list (command ) if isinstance (command , (list , tuple )) else to_args (command )
265259
266- needs_shell = any (re .search (r"\{(\w+)\}" , a ) for a in argv )
267- if needs_shell :
268- expr_argv = [re .sub (r"\{(\w+)\}" , r"${\1}" , a ) for a in argv ]
269- expr = shell_join (expr_argv )
270- return ShellWrapper (namespace , expr ).launch ()
271-
272260 if shellname in ["bash" , "sh" , "zsh" ]:
273- # 1) if user explicitly invoked a shell (bash/sh/zsh), do not wrap again
274- if argv and os .path .basename (argv [0 ]) in ["bash" , "sh" , "zsh" ]:
275- return CommandWrapper (namespace , argv ).launch ()
276-
277- # 2) if command contains {VARS}, convert to ${VARS} and run as a shell expression
278261 needs_shell = any (re .search (r"\{(\w+)\}" , a ) for a in argv )
279262 if needs_shell :
280263 expr_argv = [re .sub (r"\{(\w+)\}" , r"${\1}" , a ) for a in argv ]
281264 expr = shell_join (expr_argv )
282265 return ShellWrapper (namespace , expr ).launch ()
283266
284- # 3) otherwise run direct argv (best behavior)
285267 return CommandWrapper (namespace , argv ).launch ()
286268
287269 if shellname in ["cmd" ]:
288- # windows behavior preserved (if you need it)
289- expr = re .sub (r"\{(\w+)\}" , r"%\1%" , " " .join (argv ))
270+ expr = [re .sub (r"\{(\w+)\}" , r"%\1%" , a ) for a in argv ]
290271 return CmdWrapper (namespace , expr ).launch ()
291272
292273 return CommandWrapper (namespace , argv ).launch ()
0 commit comments