Skip to content

Commit 3ab8407

Browse files
Pass OsStr/OsString args through to the process spawned by cargo run.
To avoid breaking other (external) callers of ops::run(), this adds a new function ops::run_os() taking an &[OsString], and turns ops::run() into a wrapper (keeping its original signature) that calls run_os().
1 parent 2510c0c commit 3ab8407

File tree

5 files changed

+58
-2
lines changed

5 files changed

+58
-2
lines changed

src/bin/cargo/commands/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
7272
};
7373
}
7474
};
75-
match ops::run(&ws, &compile_opts, &values(args, "args"))? {
75+
match ops::run_os(&ws, &compile_opts, &values_os(args, "args"))? {
7676
None => Ok(()),
7777
Some(err) => {
7878
// If we never actually spawned the process then that sounds pretty

src/cargo/ops/cargo_run.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::ffi::OsString;
12
use std::iter;
23
use std::path::Path;
34

@@ -9,6 +10,15 @@ pub fn run(
910
ws: &Workspace<'_>,
1011
options: &ops::CompileOptions<'_>,
1112
args: &[String],
13+
) -> CargoResult<Option<ProcessError>> {
14+
let osargs: Vec<OsString> = args.iter().map(|s| OsString::from(s)).collect();
15+
run_os(ws, options, osargs.as_slice())
16+
}
17+
18+
pub fn run_os(
19+
ws: &Workspace<'_>,
20+
options: &ops::CompileOptions<'_>,
21+
args: &[OsString],
1222
) -> CargoResult<Option<ProcessError>> {
1323
let config = ws.config();
1424

src/cargo/ops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub use self::cargo_output_metadata::{output_metadata, ExportInfo, OutputMetadat
1212
pub use self::cargo_package::{package, PackageOpts};
1313
pub use self::cargo_pkgid::pkgid;
1414
pub use self::cargo_read_manifest::{read_package, read_packages};
15-
pub use self::cargo_run::run;
15+
pub use self::cargo_run::{run, run_os};
1616
pub use self::cargo_test::{run_benches, run_tests, TestOptions};
1717
pub use self::cargo_uninstall::uninstall;
1818
pub use self::fix::{fix, fix_maybe_exec_rustc, FixOptions};

src/cargo/util/command_prelude.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::ffi::{OsStr, OsString};
12
use std::fs;
23
use std::path::PathBuf;
34

@@ -463,6 +464,10 @@ about this warning.";
463464

464465
fn _values_of(&self, name: &str) -> Vec<String>;
465466

467+
fn _value_of_os(&self, name: &str) -> Option<&OsStr>;
468+
469+
fn _values_of_os(&self, name: &str) -> Vec<OsString>;
470+
466471
fn _is_present(&self, name: &str) -> bool;
467472
}
468473

@@ -471,13 +476,24 @@ impl<'a> ArgMatchesExt for ArgMatches<'a> {
471476
self.value_of(name)
472477
}
473478

479+
fn _value_of_os(&self, name: &str) -> Option<&OsStr> {
480+
self.value_of_os(name)
481+
}
482+
474483
fn _values_of(&self, name: &str) -> Vec<String> {
475484
self.values_of(name)
476485
.unwrap_or_default()
477486
.map(|s| s.to_string())
478487
.collect()
479488
}
480489

490+
fn _values_of_os(&self, name: &str) -> Vec<OsString> {
491+
self.values_of_os(name)
492+
.unwrap_or_default()
493+
.map(|s| s.to_os_string())
494+
.collect()
495+
}
496+
481497
fn _is_present(&self, name: &str) -> bool {
482498
self.is_present(name)
483499
}
@@ -487,6 +503,10 @@ pub fn values(args: &ArgMatches<'_>, name: &str) -> Vec<String> {
487503
args._values_of(name)
488504
}
489505

506+
pub fn values_os(args: &ArgMatches<'_>, name: &str) -> Vec<OsString> {
507+
args._values_of_os(name)
508+
}
509+
490510
#[derive(PartialEq, PartialOrd, Eq, Ord)]
491511
pub enum CommandInfo {
492512
BuiltIn { name: String, about: Option<String> },

tests/testsuite/run.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,32 @@ fn simple_with_args() {
7575
p.cargo("run hello world").run();
7676
}
7777

78+
#[cfg(unix)]
79+
#[test]
80+
fn simple_with_non_utf8_args() {
81+
use std::os::unix::ffi::OsStrExt;
82+
83+
let p = project()
84+
.file(
85+
"src/main.rs",
86+
r#"
87+
use std::ffi::OsStr;
88+
use std::os::unix::ffi::OsStrExt;
89+
90+
fn main() {
91+
assert_eq!(std::env::args_os().nth(1).unwrap(), OsStr::from_bytes(b"hello"));
92+
assert_eq!(std::env::args_os().nth(2).unwrap(), OsStr::from_bytes(b"ab\xffcd"));
93+
}
94+
"#,
95+
)
96+
.build();
97+
98+
p.cargo("run")
99+
.arg("hello")
100+
.arg(std::ffi::OsStr::from_bytes(b"ab\xFFcd"))
101+
.run();
102+
}
103+
78104
#[test]
79105
fn exit_code() {
80106
let p = project()

0 commit comments

Comments
 (0)