1use std::{
2 io::{prelude::*, Error, ErrorKind, Result},
3 process::{Command, Output, Stdio},
4};
5
6use crate::redirection;
7
8mod builtins {
9 #[derive(Debug)]
10 pub struct Builtin;
11 impl Builtin {
13 pub fn new() {}
14 }
16}
17
18#[derive(Debug)]
21pub enum Step {
22 Command(std::process::Command),
23 Builtin(builtins::Builtin),
24}
25
26#[derive(Debug)]
29pub struct StepOutput {
30 pub success: bool,
31 pub code: Option<i32>,
32 pub stdout: Vec<u8>,
33 pub stderr: Vec<u8>,
34}
35
36impl From<Output> for StepOutput {
37 fn from(output: Output) -> StepOutput {
38 Self {
39 stdout: output.stdout,
40 stderr: output.stderr,
41 code: output.status.code(),
42 success: output.status.success(),
43 }
44 }
45}
46
47impl Step {
48 pub fn new(raw_step_str: &str) -> Result<Step> {
51 let c = Step::parse_command(raw_step_str)?;
53 Ok(Step::Command(c))
54 }
55
56 fn parse_command(raw_cmd_str: &str) -> Result<Command> {
58 let cmd_string = String::from(raw_cmd_str);
59 let mut words = cmd_string.split_whitespace();
60
61 let program = words.next();
63 if program.is_none() {
64 let e = Error::new(ErrorKind::InvalidInput, "Empty Program");
65 return Err(e);
66 }
67
68 let mut command = Command::new(program.unwrap());
69
70 for w in words {
71 match w {
72 _ if redirection::Redirection::is_redirection(w) => {
74 break;
75 }
76 _ => {
78 command.arg(&w);
79 }
80 }
81 }
82 Ok(command)
83 }
84
85 pub fn run(&mut self, stdin: &[u8]) -> Result<StepOutput> {
87 match self {
88 Step::Command(c) => {
89 let mut process = c
90 .stdin(Stdio::piped())
91 .stdout(Stdio::piped())
92 .stderr(Stdio::piped())
93 .spawn()?;
94 process.stdin.as_ref().unwrap().write_all(stdin)?;
95 process.wait().unwrap();
96 Ok(StepOutput::from(process.wait_with_output()?))
97 }
98 _ => unimplemented!(),
99 }
100 }
101}