1use std::process::ExitCode;
6
7use vyder::{values, Error, ExpectArity, Module, Span, Value, ValueResult};
8
9pub fn exec(
14 arguments: &[ValueResult],
15 span: Span,
16) -> Result<(ValueResult, Option<ExitCode>), Error> {
17 let (process, string_arguments) = get_command_arguments(arguments, span.clone())?;
18
19 let output = match std::process::Command::new(process)
20 .args(string_arguments)
21 .output()
22 {
23 Ok(child) => child,
24 Err(_) => {
25 return Ok((
26 Value::new_err_value(
27 values::Str {
28 value: "failed to spawn child process".to_string(),
29 }
30 .into(),
31 span.clone(),
32 ),
33 None,
34 ));
35 }
36 };
37
38 let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
39 let stderr = String::from_utf8_lossy(&output.stderr).into_owned();
40 let exit_code = output.status.code().unwrap_or(0) as f64;
41
42 Ok((
43 Value::new_ok_value(
44 values::Map {
45 values: vec![
46 (
47 values::Str {
48 value: "stdout".to_string(),
49 }
50 .into(),
51 values::Str { value: stdout }.into(),
52 ),
53 (
54 values::Str {
55 value: "stderr".to_string(),
56 }
57 .into(),
58 values::Str { value: stderr }.into(),
59 ),
60 (
61 values::Str {
62 value: "exit_code".to_string(),
63 }
64 .into(),
65 values::Number { value: exit_code }.into(),
66 ),
67 ],
68 }
69 .into(),
70 span,
71 ),
72 None,
73 ))
74}
75
76pub fn spawn(
80 arguments: &[ValueResult],
81 span: Span,
82) -> Result<(ValueResult, Option<ExitCode>), Error> {
83 let (process, string_arguments) = get_command_arguments(arguments, span.clone())?;
84
85 let _child = match std::process::Command::new(process)
86 .args(string_arguments)
87 .spawn()
88 {
89 Ok(child) => child,
90 Err(_) => {
91 return Ok((
92 Value::new_err_value(
93 values::Str {
94 value: "failed to spawn child process".to_string(),
95 }
96 .into(),
97 span.clone(),
98 ),
99 None,
100 ));
101 }
102 };
103
104 Ok((Value::new_ok_value(values::Nil.into(), span), None))
105}
106
107fn get_command_arguments(
108 arguments: &[ValueResult],
109 span: Span,
110) -> Result<(String, Vec<String>), Error> {
111 let (process, arguments) = arguments.to_vec().expect_min::<1>(&span)?;
112 let process = process[0]
113 .clone()
114 .expect_non_error()?
115 .expect::<values::Str>()?
116 .value;
117
118 let mut string_arguments = vec![];
119 for argument in arguments {
120 string_arguments.push(argument.expect_non_error()?.expect::<values::Str>()?.value);
121 }
122
123 Ok((process, string_arguments))
124}
125
126pub fn get_module() -> Module {
127 Module::builder()
128 .function("exec", exec, true)
129 .function("spawn", spawn, true)
130 .build()
131}