mssh 0.0.0

Mssh Simple SHell. Bash interpreter/compiler. Will not support all the functionalities.
use std::process::{Child, Command, Output, Stdio};

pub type CmdResult = Result<(), std::io::Error>;

pub fn run_no_redirect(cmd: &str, args: &[String]) -> CmdResult {
    Command::new(cmd)
        .args(args)
        .stdout(Stdio::inherit())
        .stdin(Stdio::inherit())
        .stderr(Stdio::inherit())
        .spawn()?
        .wait_with_output()?;

    Ok(())
}

pub fn run_cmd_line(line: &str) -> Result<Output, std::io::Error> {
    let mut cmds: Vec<_> = line.split('|').collect();

    //eprintln!("input: {:?}", cmds);
    let first_cmd = cmds.remove(0);

    let mut args: Vec<_> = first_cmd.split(' ').filter(|s| !s.is_empty()).collect();
    //eprintln!("args before: {:?}", args);
    let cmd = args.remove(0);

    // if single command inherit programs stdin/stdout
    if cmds.len() == 0 {
        match _run_cmd(cmd, args, None, None) {
            Ok(child) => {
                return Ok(child.wait_with_output().unwrap());
            }
            Err(err) => return Err(err),
        }
    }
    // if a chain of commands pipe stdout of each process to next stdin
    let mut child = _run_cmd(cmd, args, Some(Stdio::piped()), Some(Stdio::piped()))?;

    for cmd_idx in 0..cmds.len() {
        let line = cmds[cmd_idx];
        let mut args: Vec<_> = line.split(' ').filter(|s| !s.is_empty()).collect();
        let cmd = args.remove(0);

        //eprintln!("{} : {:?}", cmd, args);
        let previous_stdout = child.stdout.unwrap();

        let new_child = _run_cmd(
            cmd,
            args,
            Some(previous_stdout.into()),
            Some(Stdio::piped()),
        )?;
        child = new_child;
    }

    let output = child.wait_with_output().unwrap();

    Ok(output)
}

fn _run_cmd(
    cmd: &str,
    args: Vec<&str>,
    stdin_redirect: Option<Stdio>,
    stdout_redirect: Option<Stdio>,
) -> Result<Child, std::io::Error> {
    // stdout must be inherited when running a single cmd
    // otherwise will have one result per line
    let stdout: Stdio = match stdout_redirect {
        Some(s) => s,
        None => Stdio::inherit(),
    };

    let stdin: Stdio = match stdin_redirect {
        Some(s) => s,
        None => Stdio::inherit(),
    };

    let child = Command::new(cmd)
        .args(args)
        .stdout(stdout)
        .stdin(stdin)
        .spawn()?;

    Ok(child)
}