1use std::{
2 io::{self, Error, ErrorKind},
3 process::Command,
4};
5
6#[derive(Debug, Clone)]
7pub struct Output {
8 pub stdout: String,
9 pub stderr: String,
10}
11
12#[allow(dead_code)]
14pub fn run(cmd: &str) -> io::Result<Output> {
15 log::info!("running: {cmd}");
16 match Command::new("sh").args(&["-c", cmd]).output() {
17 Ok(o) => {
18 let stdout = String::from_utf8_lossy(&o.stdout).as_ref().to_owned();
19 let stderr = String::from_utf8_lossy(&o.stderr).as_ref().to_owned();
20
21 if o.status.success() {
22 return Ok(Output { stdout, stderr });
23 }
24
25 match o.status.code() {
26 Some(code) => {
27 log::warn!("command failed with status code {}: {}", code, stderr);
28 Err(Error::new(
29 ErrorKind::Other,
30 format!("command failed with status code {}: {}", code, stderr),
31 ))
32 }
33 None => {
34 log::warn!(
35 "command terminated by signal with no status code: {}",
36 stderr
37 );
38 Err(Error::new(
39 ErrorKind::Other,
40 format!(
41 "command terminated by signal with no status code: {}",
42 stderr
43 ),
44 ))
45 }
46 }
47 }
48 Err(e) => {
49 log::warn!("command failed: {}", e);
50 Err(e)
51 }
52 }
53}
54
55#[test]
56fn test_bash_run() {
57 let output = run("ls -lah .").unwrap();
58 println!("stdout:\n{}", output.stdout);
59 println!("stderr:\n{}", output.stderr);
60}