Ensure that stdout and stderr are output together from the sh step

Fixes #43
This commit is contained in:
R Tyler Croy 2020-11-27 20:40:11 -08:00
parent 6b3781b746
commit f5e4ddbc81
5 changed files with 47 additions and 25 deletions

1
Cargo.lock generated
View File

@ -2121,6 +2121,7 @@ dependencies = [
name = "sh-step" name = "sh-step"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"os_pipe",
"otto-agent", "otto-agent",
"serde 1.0.117", "serde 1.0.117",
"tempfile", "tempfile",

View File

@ -63,7 +63,12 @@ async fn main() -> std::io::Result<()> {
mkdir_if_not_exists(&work_dir)?; mkdir_if_not_exists(&work_dir)?;
mkdir_if_not_exists(&cache_dir)?; mkdir_if_not_exists(&cache_dir)?;
std::env::set_var("CACHES_DIR", cache_dir.canonicalize().expect("Failed to canonicalize cache directory")); std::env::set_var(
"CACHES_DIR",
cache_dir
.canonicalize()
.expect("Failed to canonicalize cache directory"),
);
std::env::set_current_dir(work_dir)?; std::env::set_current_dir(work_dir)?;
let (sender, receiver) = channel(MAX_CONTROL_MSGS); let (sender, receiver) = channel(MAX_CONTROL_MSGS);

View File

@ -81,11 +81,11 @@ fn parse_kwarg(parser: &mut Pairs<Rule>) -> Option<(String, Value)> {
match parsed.as_rule() { match parsed.as_rule() {
Rule::IDENT => { Rule::IDENT => {
key = Some(parsed.as_str().to_string()); key = Some(parsed.as_str().to_string());
}, }
Rule::STR => { Rule::STR => {
value = Some(Value::String(parse_str(&mut parsed))); value = Some(Value::String(parse_str(&mut parsed)));
}, }
_ => {}, _ => {}
} }
} }
@ -116,12 +116,12 @@ fn parse_steps(parser: &mut Pairs<Rule>, uuid: Uuid) -> Vec<Step> {
match part.as_rule() { match part.as_rule() {
Rule::IDENT => { Rule::IDENT => {
symbol = Some(part.as_str().to_string()); symbol = Some(part.as_str().to_string());
}, }
Rule::kwarg => { Rule::kwarg => {
if let Some((key, value)) = parse_kwarg(&mut part.into_inner()) { if let Some((key, value)) = parse_kwarg(&mut part.into_inner()) {
kwargs.insert(key, value); kwargs.insert(key, value);
} }
}, }
Rule::args => { Rule::args => {
let mut pairs: Vec<Pair<Rule>> = part.into_inner().collect(); let mut pairs: Vec<Pair<Rule>> = part.into_inner().collect();
for mut pair in pairs.iter_mut() { for mut pair in pairs.iter_mut() {
@ -129,21 +129,22 @@ fn parse_steps(parser: &mut Pairs<Rule>, uuid: Uuid) -> Vec<Step> {
args.push(Value::String(parse_str(&mut pair))); args.push(Value::String(parse_str(&mut pair)));
} }
} }
}, }
_ => {}, _ => {}
} }
} }
if let Some(symbol) = symbol { if let Some(symbol) = symbol {
if kwargs.len() > 0 { if kwargs.len() > 0 {
if args.len() > 0 { if args.len() > 0 {
error!("Parsed keyword and positional arguments out, discarding positionals"); error!(
"Parsed keyword and positional arguments out, discarding positionals"
);
} }
let parameters = StepParameters::Keyword(kwargs); let parameters = StepParameters::Keyword(kwargs);
let step = Step::new(uuid, symbol, parameters); let step = Step::new(uuid, symbol, parameters);
steps.push(step); steps.push(step);
} } else {
else {
let parameters = StepParameters::Positional(args); let parameters = StepParameters::Positional(args);
let step = Step::new(uuid, symbol, parameters); let step = Step::new(uuid, symbol, parameters);
steps.push(step); steps.push(step);
@ -353,7 +354,9 @@ mod tests {
assert_eq!(step.symbol, "git"); assert_eq!(step.symbol, "git");
match &step.parameters { match &step.parameters {
StepParameters::Positional(_args) => assert!(false, "Shouldn't have positional arguments"), StepParameters::Positional(_args) => {
assert!(false, "Shouldn't have positional arguments")
}
StepParameters::Keyword(kwargs) => { StepParameters::Keyword(kwargs) => {
assert_eq!(kwargs.get("url").unwrap(), "https://example.com"); assert_eq!(kwargs.get("url").unwrap(), "https://example.com");
assert_eq!(kwargs.get("branch").unwrap(), "main"); assert_eq!(kwargs.get("branch").unwrap(), "main");
@ -382,10 +385,10 @@ mod tests {
assert_eq!(args.len(), 2); assert_eq!(args.len(), 2);
assert_eq!(args[0], "https://example.com"); assert_eq!(args[0], "https://example.com");
assert_eq!(args[1], "main"); assert_eq!(args[1], "main");
}, }
StepParameters::Keyword(_kwargs) => { StepParameters::Keyword(_kwargs) => {
assert!(false, "Not expecting keyword arguments for this step"); assert!(false, "Not expecting keyword arguments for this step");
}, }
} }
} }
} }

View File

@ -5,6 +5,7 @@ authors = ["R. Tyler Croy <rtyler@brokenco.de>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
os_pipe = "~0.9.2"
otto-agent = { path = "../../crates/agent" } otto-agent = { path = "../../crates/agent" }
serde = {version = "~1.0.117", features = ["derive"]} serde = {version = "~1.0.117", features = ["derive"]}
tempfile = "~3.1.0" tempfile = "~3.1.0"

View File

@ -2,8 +2,9 @@
* A very simple step which just invokes a shell script with some flags * A very simple step which just invokes a shell script with some flags
*/ */
use os_pipe::pipe;
use serde::Deserialize; use serde::Deserialize;
use std::io::{stderr, stdout, Write}; use std::io::{BufRead, BufReader, Write};
use std::process::Command; use std::process::Command;
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
@ -29,19 +30,30 @@ fn main() -> std::io::Result<()> {
writeln!(file, "{}", invoke.parameters.script) writeln!(file, "{}", invoke.parameters.script)
.expect("Failed to write temporary file for script"); .expect("Failed to write temporary file for script");
let output = Command::new("/bin/sh") let mut cmd = Command::new("/bin/sh");
.arg("-xe") cmd.arg("-xe");
.arg(file.path()) cmd.arg(file.path());
.output()
.expect("Failed to invoke the script");
stdout().write_all(&output.stdout).unwrap(); let (reader, writer) = pipe().unwrap();
stderr().write_all(&output.stderr).unwrap(); let writer_clone = writer.try_clone().unwrap();
cmd.stdout(writer);
cmd.stderr(writer_clone);
let mut handle = cmd.spawn()?;
drop(cmd);
let bufr = BufReader::new(reader);
for line in bufr.lines() {
if let Ok(buffer) = line {
println!("{}", buffer);
}
}
let status = handle.wait()?;
std::process::exit( std::process::exit(
output status
.status
.code() .code()
.expect("Failed to get status code of script"), .expect("Could not get exit code from subprocess"),
); );
} }