automatic 0.0.4

automatic run command throw user defined scripts
Documentation
//! Run command item with OS defined wrappers
//!
//! # Example
//!```
//!use automatic::runner::Runner;
//!
//!let result = Runner::new("true", vec![])
//!    .run()
//!    .expect("failed to execute process");
//!assert!(result.status.success());
//!```

use std::ffi::OsStr;
pub use std::io;
pub use std::process::{
    Child, ChildStderr, ChildStdin, ChildStdout, Command, ExitStatus, Output, Stdio,
};

pub struct Runned {
    process: Child,
}

impl Runned {
    pub fn wait(&mut self) -> io::Result<ExitStatus> {
        match self.process.try_wait() {
            Ok(Some(status)) => Ok(status),
            Ok(None) => self.process.wait(),
            Err(e) => Err(e),
        }
    }

    pub fn get_stdin(&mut self) -> Option<ChildStdin> {
        self.process.stdin.take()
    }

    pub fn get_stdout(&mut self) -> Option<ChildStdout> {
        self.process.stdout.take()
    }

    pub fn get_stderr(&mut self) -> Option<ChildStderr> {
        self.process.stderr.take()
    }
}

pub struct Runner {
    cmd: Command,
}

impl Runner {
    pub fn new<S: AsRef<OsStr>>(cmd: S, args: Vec<S>) -> Self {
        let mut cmd = Command::new(cmd);
        cmd.stdin(Stdio::piped());
        cmd.stdout(Stdio::piped());
        cmd.stderr(Stdio::piped());
        cmd.args(args);

        Runner { cmd }
    }

    pub fn set_stdin<T: Into<Stdio>>(&mut self, stdin: T) -> &mut Self {
        self.cmd.stdin(stdin);
        self
    }

    pub fn set_stdout<T: Into<Stdio>>(&mut self, stdout: T) -> &mut Self {
        self.cmd.stdout(stdout);
        self
    }

    pub fn set_stderr<T: Into<Stdio>>(&mut self, stderr: T) -> &mut Self {
        self.cmd.stderr(stderr);
        self
    }

    pub fn run(&mut self) -> io::Result<Output> {
        self.cmd.output()
    }

    pub fn run_async(&mut self) -> Runned {
        Runned {
            process: self.cmd.spawn().expect("failed to execute process"),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::io::{Read, Write};

    use super::*;

    #[test]
    fn create() {
        let result = Runner::new("true", vec![])
            .run()
            .expect("failed to execute process");
        assert!(result.status.success());

        let result = Runner::new("true", vec!["1", "2", "3"])
            .run()
            .expect("failed to execute process");
        assert!(result.status.success());

        let result = Runner::new("false", vec![])
            .run()
            .expect("failed to execute process");
        assert!(!result.status.success());

        let result = Runner::new("false", vec!["1", "2", "3"])
            .run()
            .expect("failed to execute process");
        assert!(!result.status.success());
    }

    #[test]
    fn create_async() {
        let result = Runner::new("true", vec![])
            .run_async()
            .wait()
            .expect("failed to wait");
        assert!(result.success());

        let result = Runner::new("true", vec!["1", "2", "3"])
            .run_async()
            .wait()
            .expect("failed to wait");
        assert!(result.success());

        let result = Runner::new("false", vec![])
            .run_async()
            .wait()
            .expect("failed to wait");
        assert!(!result.success());

        let result = Runner::new("false", vec!["1", "2", "3"])
            .run_async()
            .wait()
            .expect("failed to wait");
        assert!(!result.success());
    }

    #[test]
    fn std_in_out() {
        let mut r_async = Runner::new("cat", vec![]).run_async();
        {
            let mut input = r_async.get_stdin().unwrap();
            write!(input, "123456").expect("failed in write to pipe");
        }
        let mut output = r_async.get_stdout().unwrap();
        let mut line = String::new();
        output
            .read_to_string(&mut line)
            .expect("failed in read to string");
        assert_eq!(line, "123456");

        let mut error = r_async.get_stderr().unwrap();
        let mut line = String::new();
        error
            .read_to_string(&mut line)
            .expect("failed in read to string");
        assert_eq!(line, "");
    }

    #[test]
    fn std_pipeline() {
        let mut r_async = Runner::new("cat", vec![]).run_async();
        {
            let mut input = r_async.get_stdin().unwrap();
            write!(input, "123456").expect("failed in write to pipe");
        }

        let mut r_async_two = Runner::new("cat", vec![])
            .set_stdin(r_async.get_stdout().unwrap())
            .run_async();

        let mut output = r_async_two.get_stdout().unwrap();

        let mut line = String::new();
        output
            .read_to_string(&mut line)
            .expect("failed in read to string");
        assert_eq!(line, "123456");

        let mut error = r_async.get_stderr().unwrap();
        let mut line = String::new();
        error
            .read_to_string(&mut line)
            .expect("failed in read to string");
        assert_eq!(line, "");
    }
}