use std::process::Command;
use serde_json::{Value, json};
pub struct Done {
pub code: u8,
pub body: Value,
pub printed: bool,
}
impl Done {
pub fn plain(code: u8) -> Self {
Self {
code,
body: Value::Null,
printed: false,
}
}
pub fn with(code: u8, mut body: Value) -> Self {
if let Some(obj) = body.as_object_mut() {
obj.entry("ok".to_owned())
.or_insert(json!(code == crate::exit::OK));
obj.entry("exit".to_owned()).or_insert(json!(code));
}
Self {
code,
body,
printed: false,
}
}
pub fn printed(code: u8) -> Self {
Self {
code,
body: Value::Null,
printed: true,
}
}
}
pub fn emit(done: &Done) {
let body = if done.body.is_null() {
json!({"ok": done.code == crate::exit::OK, "exit": done.code})
} else {
done.body.clone()
};
println!(
"{}",
serde_json::to_string(&body).unwrap_or_else(|_| "{}".into())
);
}
pub fn capture(cmd: &mut Command, json_mode: bool) -> std::io::Result<(u8, String, String)> {
if json_mode {
let out = cmd.output()?;
let code = out
.status
.code()
.map_or(crate::exit::BUILD, |c| c.clamp(0, 255) as u8);
Ok((
code,
String::from_utf8_lossy(&out.stdout).into_owned(),
String::from_utf8_lossy(&out.stderr).into_owned(),
))
} else {
let status = cmd.status()?;
let code = status
.code()
.map_or(crate::exit::BUILD, |c| c.clamp(0, 255) as u8);
Ok((code, String::new(), String::new()))
}
}
pub fn done(json_mode: bool, code: u8, body: Value) -> Done {
if json_mode {
Done::with(code, body)
} else {
Done::plain(code)
}
}
pub fn fail(json_mode: bool, code: u8, error: impl std::fmt::Display) -> Done {
let error = error.to_string();
if json_mode {
Done::with(code, json!({ "error": error }))
} else {
crate::error(error);
Done::plain(code)
}
}