use crate::proto::b64_encode;
use crate::store::expand;
use serde_json::{json, Value};
use std::io::Write;
use std::process::{Command, Stdio};
pub struct ExecResult {
pub code: Option<i32>,
pub stdout: Vec<u8>,
pub stderr: Vec<u8>,
}
pub fn run_raw(req: &Value) -> Result<ExecResult, String> {
let Some(program) = req["program"].as_str() else {
return Err("no_program".to_string());
};
let mut cmd = Command::new(program);
if let Some(args) = req["args"].as_array() {
for a in args {
if let Some(s) = a.as_str() {
cmd.arg(s);
}
}
}
if let Some(cwd) = req["cwd"].as_str() {
cmd.current_dir(expand(cwd));
}
if let Some(env) = req["env"].as_object() {
for (k, v) in env {
if let Some(s) = v.as_str() {
cmd.env(k, s);
}
}
}
cmd.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
let mut child = cmd.spawn().map_err(|e| e.to_string())?;
if let Some(mut si) = child.stdin.take() {
if let Some(input) = req["stdin"].as_str() {
let _ = si.write_all(input.as_bytes());
}
}
let out = child.wait_with_output().map_err(|e| e.to_string())?;
Ok(ExecResult {
code: out.status.code(),
stdout: out.stdout,
stderr: out.stderr,
})
}
pub fn run(req: &Value) -> Value {
match run_raw(req) {
Ok(r) => json!({
"ok": true,
"code": r.code,
"stdout": b64_encode(&r.stdout),
"stderr": b64_encode(&r.stderr),
}),
Err(e) => json!({"ok": false, "err": e}),
}
}