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.
This commit is contained in:
Casey Rodarmor 2017-04-23 16:09:34 -07:00 committed by GitHub
parent 832cf7b357
commit 165e7951af
2 changed files with 50 additions and 24 deletions

View File

@ -368,7 +368,8 @@ impl<'a> Recipe<'a> {
})?; })?;
// create a command to run the script // 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 environment variables
export_env(&mut command, scope, exports)?; export_env(&mut command, scope, exports)?;
@ -1300,6 +1301,7 @@ enum RunError<'a> {
ArgumentCountMismatch{recipe: &'a str, found: usize, min: usize, max: usize}, ArgumentCountMismatch{recipe: &'a str, found: usize, min: usize, max: usize},
Backtick{token: Token<'a>, output_error: OutputError}, Backtick{token: Token<'a>, output_error: OutputError},
Code{recipe: &'a str, line_number: Option<usize>, code: i32}, Code{recipe: &'a str, line_number: Option<usize>, code: i32},
Cygpath{recipe: &'a str, output_error: OutputError},
InternalError{message: String}, InternalError{message: String},
IoError{recipe: &'a str, io_error: io::Error}, IoError{recipe: &'a str, io_error: io::Error},
Shebang{recipe: &'a str, command: String, argument: Option<String>, io_error: io::Error}, Shebang{recipe: &'a str, command: String, argument: Option<String>, io_error: io::Error},
@ -1363,6 +1365,35 @@ impl<'a> Display for RunError<'a> {
write!(f, "Recipe `{}` failed with exit code {}", recipe, code)?; 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} => { Shebang{recipe, ref command, ref argument, ref io_error} => {
if let Some(ref argument) = *argument { if let Some(ref argument) = *argument {
write!(f, "Recipe `{}` with shebang `#!{} {}` execution error: {}", write!(f, "Recipe `{}` with shebang `#!{} {}` execution error: {}",
@ -1388,7 +1419,7 @@ impl<'a> Display for RunError<'a> {
IoError{recipe, ref io_error} => { IoError{recipe, ref io_error} => {
match io_error.kind() { match io_error.kind() {
io::ErrorKind::NotFound => write!(f, 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), recipe, io_error),
io::ErrorKind::PermissionDenied => write!( io::ErrorKind::PermissionDenied => write!(
f, "Recipe `{}` could not be run because just could not run `sh`:\n{}", 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) => { OutputError::Io(ref io_error) => {
match io_error.kind() { match io_error.kind() {
io::ErrorKind::NotFound => write!( 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_error),
io::ErrorKind::PermissionDenied => write!( io::ErrorKind::PermissionDenied => write!(
f, "Backtick could not be run because just could not run `sh`:\n{}", io_error), f, "Backtick could not be run because just could not run `sh`:\n{}", io_error),

View File

@ -5,7 +5,8 @@ pub struct Platform;
pub trait PlatformInterface { pub trait PlatformInterface {
/// Construct a command equivelant to running the script at `path` with the /// Construct a command equivelant to running the script at `path` with the
/// shebang line `shebang` /// 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<process::Command, super::OutputError>;
/// Set the execute permission on the file pointed to by `path` /// Set the execute permission on the file pointed to by `path`
fn set_execute_permission(path: &Path) -> Result<(), io::Error>; fn set_execute_permission(path: &Path) -> Result<(), io::Error>;
@ -16,9 +17,11 @@ pub trait PlatformInterface {
#[cfg(unix)] #[cfg(unix)]
impl PlatformInterface for Platform { 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<process::Command, super::OutputError>
{
// shebang scripts can be executed directly on unix // 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> { fn set_execute_permission(path: &Path) -> Result<(), io::Error> {
@ -43,28 +46,20 @@ impl PlatformInterface for Platform {
#[cfg(windows)] #[cfg(windows)]
impl PlatformInterface for Platform { 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>)
let mut cmd = match env::var_os("EXEPATH") { -> Result<process::Command, super::OutputError>
Some(exepath) => { {
// On MinGW, `EXEPATH` is the root of the installation. Use it to // Translate path to the interpreter from unix style to windows style
// construct a full windows path to the binary in the shebang line. let mut cygpath = process::Command::new("cygpath");
let mut translated_command = PathBuf::from(exepath); cygpath.arg("--windows");
for part in command.split("/") { cygpath.arg(command);
translated_command.push(part);
} let mut cmd = process::Command::new(super::output(cygpath)?);
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)
}
};
if let Some(argument) = argument { if let Some(argument) = argument {
cmd.arg(argument); cmd.arg(argument);
} }
cmd.arg(path); cmd.arg(path);
cmd Ok(cmd)
} }
fn set_execute_permission(_path: &Path) -> Result<(), io::Error> { fn set_execute_permission(_path: &Path) -> Result<(), io::Error> {