diff --git a/Cargo.lock b/Cargo.lock index be7e890a9..bc9874f2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,6 +56,7 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "which 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -137,6 +138,11 @@ name = "serde" version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "shell-escape" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "toml" version = "0.5.5" @@ -200,6 +206,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" +"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml index e4befed2c..cafcc4a46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ rustc_version = "0.2" semver = "0.9" toml = "0.5" which = { version = "3.1.0", default_features = false } +shell-escape = "0.1.4" [target.'cfg(not(windows))'.dependencies] nix = "0.15" diff --git a/src/docker.rs b/src/docker.rs index 24e129910..fccad253b 100644 --- a/src/docker.rs +++ b/src/docker.rs @@ -8,7 +8,7 @@ use error_chain::bail; use crate::{Target, Toml}; use crate::cargo::Root; use crate::errors::*; -use crate::extensions::CommandExt; +use crate::extensions::{CommandExt, SafeCommand}; use crate::id; const DOCKER_IMAGES: &[&str] = &include!(concat!(env!("OUT_DIR"), "/docker-images.rs")); @@ -72,9 +72,9 @@ pub fn run(target: &Target, fs::create_dir(&xargo_dir).ok(); let mut cmd = if uses_xargo { - Command::new("xargo") + SafeCommand::new("xargo") } else { - Command::new("cargo") + SafeCommand::new("cargo") }; cmd.args(args); diff --git a/src/extensions.rs b/src/extensions.rs index 96cc91cba..81540a6f8 100644 --- a/src/extensions.rs +++ b/src/extensions.rs @@ -1,4 +1,6 @@ +use std::borrow::Cow; use std::process::{Command, ExitStatus}; +use std::fmt; use crate::errors::*; @@ -50,3 +52,56 @@ impl CommandExt for Command { .chain_err(|| format!("`{:?}` output was not UTF-8", self))?) } } + +pub struct SafeCommand { + program: String, + args: Vec, +} + +impl SafeCommand { + pub fn new(program: S) -> Self { + let program = program.to_string(); + SafeCommand { + program, + args: Vec::new(), + } + } + + pub fn arg<'b, S>(&mut self, arg: &S) -> &mut Self + where + S: ToString, + { + self.args.push(arg.to_string()); + self + } + + pub fn args(&mut self, args: I) -> &mut Self + where + I: IntoIterator, + S: ToString, + { + for arg in args { + self.arg(&arg); + } + self + } +} + +impl fmt::Debug for SafeCommand { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(&shell_escape::escape(Cow::from(&self.program)))?; + for arg in &self.args { + f.write_str(" ")?; + f.write_str(&shell_escape::escape(Cow::from(arg)))?; + } + Ok(()) + } +} + +impl From for Command { + fn from(s: SafeCommand) -> Self { + let mut cmd = Command::new(&s.program); + cmd.args(&s.args); + cmd + } +}