Skip to content

Commit

Permalink
Pass OsStr/OsString args through to the process spawned by cargo run.
Browse files Browse the repository at this point in the history
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().
  • Loading branch information
johnbartholomew committed Apr 14, 2019
1 parent 2510c0c commit 3ab8407
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/bin/cargo/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
};
}
};
match ops::run(&ws, &compile_opts, &values(args, "args"))? {
match ops::run_os(&ws, &compile_opts, &values_os(args, "args"))? {
None => Ok(()),
Some(err) => {
// If we never actually spawned the process then that sounds pretty
Expand Down
10 changes: 10 additions & 0 deletions src/cargo/ops/cargo_run.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::ffi::OsString;
use std::iter;
use std::path::Path;

Expand All @@ -9,6 +10,15 @@ pub fn run(
ws: &Workspace<'_>,
options: &ops::CompileOptions<'_>,
args: &[String],
) -> CargoResult<Option<ProcessError>> {
let osargs: Vec<OsString> = args.iter().map(|s| OsString::from(s)).collect();
run_os(ws, options, osargs.as_slice())
}

pub fn run_os(
ws: &Workspace<'_>,
options: &ops::CompileOptions<'_>,
args: &[OsString],
) -> CargoResult<Option<ProcessError>> {
let config = ws.config();

Expand Down
2 changes: 1 addition & 1 deletion src/cargo/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use self::cargo_output_metadata::{output_metadata, ExportInfo, OutputMetadat
pub use self::cargo_package::{package, PackageOpts};
pub use self::cargo_pkgid::pkgid;
pub use self::cargo_read_manifest::{read_package, read_packages};
pub use self::cargo_run::run;
pub use self::cargo_run::{run, run_os};
pub use self::cargo_test::{run_benches, run_tests, TestOptions};
pub use self::cargo_uninstall::uninstall;
pub use self::fix::{fix, fix_maybe_exec_rustc, FixOptions};
Expand Down
20 changes: 20 additions & 0 deletions src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::PathBuf;

Expand Down Expand Up @@ -463,6 +464,10 @@ about this warning.";

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

fn _value_of_os(&self, name: &str) -> Option<&OsStr>;

fn _values_of_os(&self, name: &str) -> Vec<OsString>;

fn _is_present(&self, name: &str) -> bool;
}

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

fn _value_of_os(&self, name: &str) -> Option<&OsStr> {
self.value_of_os(name)
}

fn _values_of(&self, name: &str) -> Vec<String> {
self.values_of(name)
.unwrap_or_default()
.map(|s| s.to_string())
.collect()
}

fn _values_of_os(&self, name: &str) -> Vec<OsString> {
self.values_of_os(name)
.unwrap_or_default()
.map(|s| s.to_os_string())
.collect()
}

fn _is_present(&self, name: &str) -> bool {
self.is_present(name)
}
Expand All @@ -487,6 +503,10 @@ pub fn values(args: &ArgMatches<'_>, name: &str) -> Vec<String> {
args._values_of(name)
}

pub fn values_os(args: &ArgMatches<'_>, name: &str) -> Vec<OsString> {
args._values_of_os(name)
}

#[derive(PartialEq, PartialOrd, Eq, Ord)]
pub enum CommandInfo {
BuiltIn { name: String, about: Option<String> },
Expand Down
26 changes: 26 additions & 0 deletions tests/testsuite/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,32 @@ fn simple_with_args() {
p.cargo("run hello world").run();
}

#[cfg(unix)]
#[test]
fn simple_with_non_utf8_args() {
use std::os::unix::ffi::OsStrExt;

let p = project()
.file(
"src/main.rs",
r#"
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
fn main() {
assert_eq!(std::env::args_os().nth(1).unwrap(), OsStr::from_bytes(b"hello"));
assert_eq!(std::env::args_os().nth(2).unwrap(), OsStr::from_bytes(b"ab\xffcd"));
}
"#,
)
.build();

p.cargo("run")
.arg("hello")
.arg(std::ffi::OsStr::from_bytes(b"ab\xFFcd"))
.run();
}

#[test]
fn exit_code() {
let p = project()
Expand Down

0 comments on commit 3ab8407

Please sign in to comment.