use std::process::ExitCode;
use vyder::{values, Error, ExpectArity, Module, Span, Value, ValueResult};
pub fn exec(
arguments: &[ValueResult],
span: Span,
) -> Result<(ValueResult, Option<ExitCode>), Error> {
let (process, string_arguments) = get_command_arguments(arguments, span.clone())?;
let output = match std::process::Command::new(process)
.args(string_arguments)
.output()
{
Ok(child) => child,
Err(_) => {
return Ok((
Value::new_err_value(
values::Str {
value: "failed to spawn child process".to_string(),
}
.into(),
span.clone(),
),
None,
));
}
};
let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
let exit_code = output.status.code().unwrap_or(0) as f64;
Ok((
Value::new_ok_value(
values::Map {
values: vec![
(
values::Str {
value: "stdout".to_string(),
}
.into(),
values::Str { value: stdout }.into(),
),
(
values::Str {
value: "stderr".to_string(),
}
.into(),
values::Str { value: stderr }.into(),
),
(
values::Str {
value: "exit_code".to_string(),
}
.into(),
values::Number { value: exit_code }.into(),
),
],
}
.into(),
span,
),
None,
))
}
pub fn spawn(
arguments: &[ValueResult],
span: Span,
) -> Result<(ValueResult, Option<ExitCode>), Error> {
let (process, string_arguments) = get_command_arguments(arguments, span.clone())?;
let _child = match std::process::Command::new(process)
.args(string_arguments)
.spawn()
{
Ok(child) => child,
Err(_) => {
return Ok((
Value::new_err_value(
values::Str {
value: "failed to spawn child process".to_string(),
}
.into(),
span.clone(),
),
None,
));
}
};
Ok((Value::new_ok_value(values::Nil.into(), span), None))
}
fn get_command_arguments(
arguments: &[ValueResult],
span: Span,
) -> Result<(String, Vec<String>), Error> {
let (process, arguments) = arguments.to_vec().expect_min::<1>(&span)?;
let process = process[0]
.clone()
.expect_non_error()?
.expect::<values::Str>()?
.value;
let mut string_arguments = vec![];
for argument in arguments {
string_arguments.push(argument.expect_non_error()?.expect::<values::Str>()?.value);
}
Ok((process, string_arguments))
}
pub fn get_module() -> Module {
Module::builder()
.function("exec", exec, true)
.function("spawn", spawn, true)
.build()
}