diff --git a/tools/cli/src/utils.rs b/tools/cli/src/utils.rs index 5d59757a..cdd92266 100644 --- a/tools/cli/src/utils.rs +++ b/tools/cli/src/utils.rs @@ -14,6 +14,8 @@ * limitations under the License. */ +use std::fmt::Formatter; +use std::io::ErrorKind; use std::process::Command; use std::process::Stdio; @@ -32,13 +34,48 @@ fn run_command>( mut command: Command, stdout_config: T, ) -> Result { - let process = command.stdout(stdout_config).spawn()?; + let process = command + .stdout(stdout_config) + .spawn() + .map_err(|e| process_command_run_error(e, &command))?; let output = process.wait_with_output()?; if !output.status.success() { - anyhow::bail!("failed to execute, exited with {}", output.status) + anyhow::bail!( + r#"command `{}` exited with {}"#, + PrintCommand(&command), + output.status + ) } let stdout = String::from_utf8_lossy(&output.stdout).into_owned(); Ok(stdout) } + +struct PrintCommand<'c>(&'c Command); + +impl<'c> std::fmt::Display for PrintCommand<'c> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.get_program().to_string_lossy())?; + for arg in self.0.get_args() { + write!(f, " {}", arg.to_string_lossy())?; + } + + Ok(()) + } +} + +fn process_command_run_error(e: std::io::Error, command: &Command) -> anyhow::Error { + if e.kind() == ErrorKind::NotFound { + anyhow::anyhow!( + r#"cannot run `{}`: executable not found in $PATH"#, + command.get_program().to_string_lossy(), + ) + } else { + anyhow::anyhow!( + r#"cannot run `{}`: {}"#, + command.get_program().to_string_lossy(), + e + ) + } +}