From 165e7951afe33f4d121cf83d8740bf7f28770323 Mon Sep 17 00:00:00 2001 From: Casey Rodarmor Date: Sun, 23 Apr 2017 16:09:34 -0700 Subject: [PATCH] Use cygpath to translate paths on windows (#188) I was previous doing it manually, which failed when running in powershell in a Github Desktop for windows. Use the `cygpath` utility instead. --- src/lib.rs | 37 ++++++++++++++++++++++++++++++++++--- src/platform.rs | 37 ++++++++++++++++--------------------- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ebbfb09..fa65899 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -368,7 +368,8 @@ impl<'a> Recipe<'a> { })?; // create a command to run the script - let mut command = Platform::make_shebang_command(&path, shebang_command, shebang_argument); + let mut command = Platform::make_shebang_command(&path, shebang_command, shebang_argument) + .map_err(|output_error| RunError::Cygpath{recipe: self.name, output_error: output_error})?; // export environment variables export_env(&mut command, scope, exports)?; @@ -1300,6 +1301,7 @@ enum RunError<'a> { ArgumentCountMismatch{recipe: &'a str, found: usize, min: usize, max: usize}, Backtick{token: Token<'a>, output_error: OutputError}, Code{recipe: &'a str, line_number: Option, code: i32}, + Cygpath{recipe: &'a str, output_error: OutputError}, InternalError{message: String}, IoError{recipe: &'a str, io_error: io::Error}, Shebang{recipe: &'a str, command: String, argument: Option, io_error: io::Error}, @@ -1363,6 +1365,35 @@ impl<'a> Display for RunError<'a> { write!(f, "Recipe `{}` failed with exit code {}", recipe, code)?; } }, + Cygpath{recipe, ref output_error} => match *output_error { + OutputError::Code(code) => { + write!(f, "Cygpath failed with exit code {} while translating recipe `{}` \ + shebang interpreter path", code, recipe)?; + } + OutputError::Signal(signal) => { + write!(f, "Cygpath terminated by signal {} while translating recipe `{}` \ + shebang interpreter path", signal, recipe)?; + } + OutputError::Unknown => { + write!(f, "Cygpath experienced an unknown failure while translating recipe `{}` \ + shebang interpreter path", recipe)?; + } + OutputError::Io(ref io_error) => { + match io_error.kind() { + io::ErrorKind::NotFound => write!( + f, "Could not find `cygpath` executable to translate recipe `{}` \ + shebang interpreter path:\n{}", recipe, io_error), + io::ErrorKind::PermissionDenied => write!( + f, "Could not run `cygpath` executable to translate recipe `{}` \ + shebang interpreter path:\n{}", recipe, io_error), + _ => write!(f, "Could not run `cygpath` executable:\n{}", io_error), + }?; + } + OutputError::Utf8(ref utf8_error) => { + write!(f, "Cygpath successfully translated recipe `{}` shebang interpreter path, \ + but output was not utf8: {}", recipe, utf8_error)?; + } + }, Shebang{recipe, ref command, ref argument, ref io_error} => { if let Some(ref argument) = *argument { write!(f, "Recipe `{}` with shebang `#!{} {}` execution error: {}", @@ -1388,7 +1419,7 @@ impl<'a> Display for RunError<'a> { IoError{recipe, ref io_error} => { match io_error.kind() { io::ErrorKind::NotFound => write!(f, - "Recipe `{}` could not be run because just could not find `sh` the command:\n{}", + "Recipe `{}` could not be run because just could not find `sh`:\n{}", recipe, io_error), io::ErrorKind::PermissionDenied => write!( f, "Recipe `{}` could not be run because just could not run `sh`:\n{}", @@ -1417,7 +1448,7 @@ impl<'a> Display for RunError<'a> { OutputError::Io(ref io_error) => { match io_error.kind() { io::ErrorKind::NotFound => write!( - f, "Backtick could not be run because just could not find `sh` the command:\n{}", + f, "Backtick could not be run because just could not find `sh`:\n{}", io_error), io::ErrorKind::PermissionDenied => write!( f, "Backtick could not be run because just could not run `sh`:\n{}", io_error), diff --git a/src/platform.rs b/src/platform.rs index ac403db..fc271d6 100644 --- a/src/platform.rs +++ b/src/platform.rs @@ -5,7 +5,8 @@ pub struct Platform; pub trait PlatformInterface { /// Construct a command equivelant to running the script at `path` with the /// shebang line `shebang` - fn make_shebang_command(path: &Path, command: &str, argument: Option<&str>) -> process::Command; + fn make_shebang_command(path: &Path, command: &str, argument: Option<&str>) + -> Result; /// Set the execute permission on the file pointed to by `path` fn set_execute_permission(path: &Path) -> Result<(), io::Error>; @@ -16,9 +17,11 @@ pub trait PlatformInterface { #[cfg(unix)] impl PlatformInterface for Platform { - fn make_shebang_command(path: &Path, _command: &str, _argument: Option<&str>) -> process::Command { + fn make_shebang_command(path: &Path, _command: &str, _argument: Option<&str>) + -> Result + { // shebang scripts can be executed directly on unix - process::Command::new(path) + Ok(process::Command::new(path)) } fn set_execute_permission(path: &Path) -> Result<(), io::Error> { @@ -43,28 +46,20 @@ impl PlatformInterface for Platform { #[cfg(windows)] impl PlatformInterface for Platform { - fn make_shebang_command(path: &Path, command: &str, argument: Option<&str>) -> process::Command { - let mut cmd = match env::var_os("EXEPATH") { - Some(exepath) => { - // On MinGW, `EXEPATH` is the root of the installation. Use it to - // construct a full windows path to the binary in the shebang line. - let mut translated_command = PathBuf::from(exepath); - for part in command.split("/") { - translated_command.push(part); - } - process::Command::new(translated_command) - } - None => { - // We're not on MinGW >_< The path in the shebang might be a windows - // path, in which case it'll work, so just use it and hope for the best. - process::Command::new(command) - } - }; + fn make_shebang_command(path: &Path, command: &str, argument: Option<&str>) + -> Result + { + // Translate path to the interpreter from unix style to windows style + let mut cygpath = process::Command::new("cygpath"); + cygpath.arg("--windows"); + cygpath.arg(command); + + let mut cmd = process::Command::new(super::output(cygpath)?); if let Some(argument) = argument { cmd.arg(argument); } cmd.arg(path); - cmd + Ok(cmd) } fn set_execute_permission(_path: &Path) -> Result<(), io::Error> {