Rollup merge of #77728 - lygstate:master, r=Amanieu
Expose force_quotes on Windows. On Windows, the arg quotes and not quotes have different effect for the program it called, if the program called are msys2/cygwin program. Refer to https://github.com/msys2/MSYS2-packages/issues/2176 This also solve the issues comes from https://internals.rust-lang.org/t/std-process-on-windows-is-escaping-raw-literals-which-causes-problems-with-chaining-commands/8163 Tracking issue: https://github.com/rust-lang/rust/issues/82227
This commit is contained in:
commit
db59950b6d
@ -105,6 +105,22 @@ pub trait CommandExt: Sealed {
|
||||
/// [1]: https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
|
||||
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
|
||||
fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
|
||||
|
||||
/// Forces all arguments to be wrapped in quote (`"`) characters.
|
||||
///
|
||||
/// This is useful for passing arguments to [MSYS2/Cygwin][1] based
|
||||
/// executables: these programs will expand unquoted arguments containing
|
||||
/// wildcard characters (`?` and `*`) by searching for any file paths
|
||||
/// matching the wildcard pattern.
|
||||
///
|
||||
/// Adding quotes has no effect when passing arguments to programs
|
||||
/// that use [msvcrt][2]. This includes programs built with both
|
||||
/// MinGW and MSVC.
|
||||
///
|
||||
/// [1]: <https://github.com/msys2/MSYS2-packages/issues/2176>
|
||||
/// [2]: <https://msdn.microsoft.com/en-us/library/17w5ykft.aspx>
|
||||
#[unstable(feature = "windows_process_extensions_force_quotes", issue = "82227")]
|
||||
fn force_quotes(&mut self, enabled: bool) -> &mut process::Command;
|
||||
}
|
||||
|
||||
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
|
||||
@ -113,4 +129,9 @@ fn creation_flags(&mut self, flags: u32) -> &mut process::Command {
|
||||
self.as_inner_mut().creation_flags(flags);
|
||||
self
|
||||
}
|
||||
|
||||
fn force_quotes(&mut self, enabled: bool) -> &mut process::Command {
|
||||
self.as_inner_mut().force_quotes(enabled);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ pub struct Command {
|
||||
stdin: Option<Stdio>,
|
||||
stdout: Option<Stdio>,
|
||||
stderr: Option<Stdio>,
|
||||
force_quotes_enabled: bool,
|
||||
}
|
||||
|
||||
pub enum Stdio {
|
||||
@ -109,6 +110,7 @@ pub fn new(program: &OsStr) -> Command {
|
||||
stdin: None,
|
||||
stdout: None,
|
||||
stderr: None,
|
||||
force_quotes_enabled: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +136,10 @@ pub fn creation_flags(&mut self, flags: u32) {
|
||||
self.flags = flags;
|
||||
}
|
||||
|
||||
pub fn force_quotes(&mut self, enabled: bool) {
|
||||
self.force_quotes_enabled = enabled;
|
||||
}
|
||||
|
||||
pub fn get_program(&self) -> &OsStr {
|
||||
&self.program
|
||||
}
|
||||
@ -181,7 +187,7 @@ pub fn spawn(
|
||||
si.dwFlags = c::STARTF_USESTDHANDLES;
|
||||
|
||||
let program = program.as_ref().unwrap_or(&self.program);
|
||||
let mut cmd_str = make_command_line(program, &self.args)?;
|
||||
let mut cmd_str = make_command_line(program, &self.args, self.force_quotes_enabled)?;
|
||||
cmd_str.push(0); // add null terminator
|
||||
|
||||
// stolen from the libuv code.
|
||||
@ -467,7 +473,7 @@ fn zeroed_process_information() -> c::PROCESS_INFORMATION {
|
||||
|
||||
// Produces a wide string *without terminating null*; returns an error if
|
||||
// `prog` or any of the `args` contain a nul.
|
||||
fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
|
||||
fn make_command_line(prog: &OsStr, args: &[OsString], force_quotes: bool) -> io::Result<Vec<u16>> {
|
||||
// Encode the command and arguments in a command line string such
|
||||
// that the spawned process may recover them using CommandLineToArgvW.
|
||||
let mut cmd: Vec<u16> = Vec::new();
|
||||
@ -476,7 +482,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
|
||||
append_arg(&mut cmd, prog, true)?;
|
||||
for arg in args {
|
||||
cmd.push(' ' as u16);
|
||||
append_arg(&mut cmd, arg, false)?;
|
||||
append_arg(&mut cmd, arg, force_quotes)?;
|
||||
}
|
||||
return Ok(cmd);
|
||||
|
||||
|
@ -3,29 +3,41 @@
|
||||
|
||||
#[test]
|
||||
fn test_make_command_line() {
|
||||
fn test_wrapper(prog: &str, args: &[&str]) -> String {
|
||||
fn test_wrapper(prog: &str, args: &[&str], force_quotes: bool) -> String {
|
||||
let command_line = &make_command_line(
|
||||
OsStr::new(prog),
|
||||
&args.iter().map(|a| OsString::from(a)).collect::<Vec<OsString>>(),
|
||||
force_quotes,
|
||||
)
|
||||
.unwrap();
|
||||
String::from_utf16(command_line).unwrap()
|
||||
}
|
||||
|
||||
assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc");
|
||||
assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"], false), "\"prog\" aaa bbb ccc");
|
||||
|
||||
assert_eq!(
|
||||
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]),
|
||||
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"], false),
|
||||
"\"C:\\Program Files\\blah\\blah.exe\" aaa"
|
||||
);
|
||||
assert_eq!(
|
||||
test_wrapper("C:\\Program Files\\test", &["aa\"bb"]),
|
||||
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], false),
|
||||
"\"C:\\Program Files\\blah\\blah.exe\" aaa v*"
|
||||
);
|
||||
assert_eq!(
|
||||
test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa", "v*"], true),
|
||||
"\"C:\\Program Files\\blah\\blah.exe\" \"aaa\" \"v*\""
|
||||
);
|
||||
assert_eq!(
|
||||
test_wrapper("C:\\Program Files\\test", &["aa\"bb"], false),
|
||||
"\"C:\\Program Files\\test\" aa\\\"bb"
|
||||
);
|
||||
assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\"");
|
||||
assert_eq!(test_wrapper("echo", &["\" \\\" \\", "\\"]), "\"echo\" \"\\\" \\\\\\\" \\\\\" \\");
|
||||
assert_eq!(test_wrapper("echo", &["a b c"], false), "\"echo\" \"a b c\"");
|
||||
assert_eq!(
|
||||
test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]),
|
||||
test_wrapper("echo", &["\" \\\" \\", "\\"], false),
|
||||
"\"echo\" \"\\\" \\\\\\\" \\\\\" \\"
|
||||
);
|
||||
assert_eq!(
|
||||
test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[], false),
|
||||
"\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\""
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user