Skip to content

Commit 42b29b7

Browse files
authored
fix(runner): preserve internal quotes in cmd strings on Windows (#56)
1 parent b405b21 commit 42b29b7

1 file changed

Lines changed: 23 additions & 9 deletions

File tree

src/runner.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,7 @@ fn execute_step_def(
176176
fn execute_command(cmd: &str, work_dir: &Path, env: &HashMap<String, String>) -> Result<()> {
177177
println!("$ {}", cmd);
178178

179-
let mut command = if cfg!(target_os = "windows") {
180-
let mut c = Command::new("cmd");
181-
c.args(["/C", cmd]);
182-
c
183-
} else {
184-
let mut c = Command::new("sh");
185-
c.args(["-c", cmd]);
186-
c
187-
};
179+
let mut command = build_shell_command(cmd);
188180

189181
command.current_dir(work_dir);
190182
command.envs(env);
@@ -200,3 +192,25 @@ fn execute_command(cmd: &str, work_dir: &Path, env: &HashMap<String, String>) ->
200192

201193
Ok(())
202194
}
195+
196+
#[cfg(not(target_os = "windows"))]
197+
fn build_shell_command(cmd: &str) -> Command {
198+
let mut c = Command::new("sh");
199+
c.args(["-c", cmd]);
200+
c
201+
}
202+
203+
// On Windows, bypass Rust's MSVCRT-style arg escaping (which uses backslash
204+
// escapes that cmd.exe does not understand) and write the command line for
205+
// cmd.exe directly. `/S` makes cmd.exe deterministically strip exactly the
206+
// outermost pair of quotes, preserving any internal quotes — so a cmd like
207+
// `go build -ldflags="-s -w"` reaches its target program intact.
208+
#[cfg(target_os = "windows")]
209+
fn build_shell_command(cmd: &str) -> Command {
210+
use std::os::windows::process::CommandExt;
211+
let mut c = Command::new("cmd");
212+
c.raw_arg("/S");
213+
c.raw_arg("/C");
214+
c.raw_arg(format!("\"{cmd}\""));
215+
c
216+
}

0 commit comments

Comments
 (0)