From f5bbaef82bb092d4e77859544af3f80e82641c9d Mon Sep 17 00:00:00 2001 From: Thomas O'Donnell Date: Wed, 27 Nov 2019 23:03:08 +0100 Subject: [PATCH] chore: Add a helper function for executing commands (#660) --- src/utils.rs | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/src/utils.rs b/src/utils.rs index c873f45a..98dd4c3b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,7 @@ use std::fs::File; use std::io::{Read, Result}; use std::path::Path; +use std::process::Command; /// Return the string contents of a file pub fn read_file>(file_name: P) -> Result { @@ -10,3 +11,97 @@ pub fn read_file>(file_name: P) -> Result { file.read_to_string(&mut data)?; Ok(data) } + +#[derive(Debug)] +pub struct CommandOutput { + pub stdout: String, + pub stderr: String, +} + +impl PartialEq for CommandOutput { + fn eq(&self, other: &Self) -> bool { + self.stdout == other.stdout && self.stderr == other.stderr + } +} + +/// Execute a command and return the output on stdout and stderr if sucessful +pub fn exec_cmd(cmd: &str, args: &[&str]) -> Option { + log::trace!("Executing command '{:?}' with args '{:?}'", cmd, args); + match Command::new(cmd).args(args).output() { + Ok(output) => { + let stdout_string = String::from_utf8(output.stdout).unwrap(); + let stderr_string = String::from_utf8(output.stderr).unwrap(); + + if !output.status.success() { + log::trace!("Non-zero exit code '{:?}'", output.status.code()); + log::trace!("stdout: {}", stdout_string); + log::trace!("stderr: {}", stderr_string); + return None; + } + + Some(CommandOutput { + stdout: stdout_string, + stderr: stderr_string, + }) + } + Err(_) => None, + } +} + +#[cfg(test)] +#[cfg(not(windows))] // While the exec_cmd should work on Windows these tests assume a Unix-like environment. +mod tests { + use super::*; + + #[test] + fn exec_no_output() { + let result = exec_cmd("true", &[]); + let expected = Some(CommandOutput { + stdout: String::from(""), + stderr: String::from(""), + }); + + assert_eq!(result, expected) + } + + #[test] + fn exec_with_output_stdout() { + let result = exec_cmd("/bin/echo", &["-n", "hello"]); + let expected = Some(CommandOutput { + stdout: String::from("hello"), + stderr: String::from(""), + }); + + assert_eq!(result, expected) + } + + #[test] + fn exec_with_output_stderr() { + let result = exec_cmd("/bin/sh", &["-c", "echo hello >&2"]); + let expected = Some(CommandOutput { + stdout: String::from(""), + stderr: String::from("hello\n"), + }); + + assert_eq!(result, expected) + } + + #[test] + fn exec_with_output_both() { + let result = exec_cmd("/bin/sh", &["-c", "echo hello; echo world >&2"]); + let expected = Some(CommandOutput { + stdout: String::from("hello\n"), + stderr: String::from("world\n"), + }); + + assert_eq!(result, expected) + } + + #[test] + fn exec_with_non_zero_exit_code() { + let result = exec_cmd("false", &[]); + let expected = None; + + assert_eq!(result, expected) + } +}