mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-04-20 11:35:48 +00:00
feat: basic runner that can capture stdout
This commit is contained in:
parent
5116f7d794
commit
9880b8e4e7
2 changed files with 123 additions and 0 deletions
|
@ -1,4 +1,5 @@
|
|||
pub mod profile;
|
||||
pub mod runner;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
|
|
122
src/runner.rs
Normal file
122
src/runner.rs
Normal file
|
@ -0,0 +1,122 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
io::{BufRead, BufReader},
|
||||
process::{Child, Command, Stdio},
|
||||
};
|
||||
|
||||
pub struct Runner {
|
||||
environment: HashMap<String, String>,
|
||||
command: String,
|
||||
args: Vec<String>,
|
||||
stdout: Vec<String>,
|
||||
stderr: Vec<String>,
|
||||
process: Option<Child>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum RunnerStatus {
|
||||
Running,
|
||||
Stopped,
|
||||
}
|
||||
|
||||
impl Runner {
|
||||
pub fn new(environment: HashMap<String, String>, command: String, args: Vec<String>) -> Runner {
|
||||
Runner {
|
||||
environment,
|
||||
command,
|
||||
args,
|
||||
stdout: Vec::new(),
|
||||
stderr: Vec::new(),
|
||||
process: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
self.process = Some(
|
||||
Command::new(&self.command)
|
||||
.args(&self.args)
|
||||
.envs(self.environment.clone())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.expect("Failed to execute runner"),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn terminate(&mut self) {
|
||||
match self.process.as_mut() {
|
||||
None => {
|
||||
println!("Runner already stopped")
|
||||
}
|
||||
Some(proc) => {
|
||||
proc.kill().expect("Failed to kill process");
|
||||
proc.wait().expect("Failed to wait for process");
|
||||
self.process = None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn status(&mut self) -> RunnerStatus {
|
||||
match self.process.as_mut() {
|
||||
None => RunnerStatus::Stopped,
|
||||
Some(proc) => match proc.try_wait() {
|
||||
Ok(_) => RunnerStatus::Stopped,
|
||||
Err(_) => RunnerStatus::Running,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn flush_out(&mut self) {
|
||||
match self.process.as_mut() {
|
||||
None => (),
|
||||
Some(proc) => {
|
||||
let out = proc.stdout.take().expect("Unable to read stout");
|
||||
let mut reader = BufReader::new(out);
|
||||
let mut bytes_read = 1;
|
||||
let mut buf = "".to_string();
|
||||
while bytes_read != 0 {
|
||||
bytes_read = match reader.read_line(&mut buf) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(_) => 0,
|
||||
};
|
||||
self.stdout.push(buf.clone());
|
||||
buf.clear();
|
||||
}
|
||||
|
||||
let err = proc.stderr.take().expect("Unable to read stderr");
|
||||
let mut err_reader = BufReader::new(err);
|
||||
bytes_read = 1;
|
||||
while bytes_read != 0 {
|
||||
bytes_read = match err_reader.read_line(&mut buf) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(_) => 0,
|
||||
};
|
||||
self.stderr.push(buf.clone());
|
||||
buf.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{Runner, RunnerStatus};
|
||||
use core::time;
|
||||
use std::{collections::HashMap, thread::sleep};
|
||||
|
||||
#[test]
|
||||
fn can_run_command_and_read_env() {
|
||||
let mut env = HashMap::new();
|
||||
env.insert("REX2TEST".to_string(), "Lorem ipsum dolor".to_string());
|
||||
let mut runner = Runner::new(env, "bash".into(), vec!["-c".into(), "echo \"REX2TEST: $REX2TEST\"".into()]);
|
||||
runner.start();
|
||||
while runner.status() == RunnerStatus::Running {
|
||||
sleep(time::Duration::from_millis(10));
|
||||
}
|
||||
runner.flush_out();
|
||||
assert_eq!(runner.status(), RunnerStatus::Stopped);
|
||||
assert_eq!(runner.stdout.len(), 2);
|
||||
assert_eq!(runner.stdout.get(0).unwrap(), "REX2TEST: Lorem ipsum dolor\n");
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue