wlambda/stdlib/
process.rs1use crate::compiler::*;
2use crate::vval::*;
3use std::process::{Command, Child, Stdio};
4use std::rc::Rc;
5use std::cell::RefCell;
6
7#[derive(Clone)]
8struct VChildProcess {
9 child: Rc<RefCell<Child>>,
10 id: u32,
11}
12
13impl VValUserData for VChildProcess {
14 fn s(&self) -> String { format!("$<ChildProcess:pid={}>", self.id) }
15 fn i(&self) -> i64 { self.id as i64 }
16 fn as_any(&mut self) -> &mut dyn std::any::Any { self }
17 fn clone_ud(&self) -> Box<dyn VValUserData> {
18 Box::new(self.clone())
19 }
20}
21
22pub fn add_to_symtable(st: &mut SymbolTable) {
23 st.fun("process:spawn", |env: &mut Env, argc: usize| {
24 let cmd_exe = env.arg(0).deref();
25
26 let mut cmd =
27 cmd_exe.with_s_ref(|s| Command::new(s));
28
29 if argc > 1 {
30 let args = env.arg(1).deref();
31 for a in args.iter() {
32 a.0.with_s_ref(|s| cmd.arg(s));
33 }
34 }
35
36 if env.arg(2).with_s_ref(|s| s == "inherit_out") {
37 cmd.stdin(Stdio::null());
38
39 } else if env.arg(2).with_s_ref(|s| s == "inherit_all") {
40 } else {
43 cmd.stdin(Stdio::null());
44 cmd.stdout(Stdio::null());
45 cmd.stderr(Stdio::null());
46 }
47
48 let child =
49 match cmd.spawn() {
50 Ok(child) => child,
51 Err(e) => {
52 return Ok(env.new_err(
53 format!("Error executing '{}': {}", cmd_exe.s(), e)));
54 },
55 };
56
57 let id = child.id();
58 let child = Rc::new(RefCell::new(child));
59 Ok(VVal::new_usr(VChildProcess { child, id }))
60 }, Some(1), Some(3), false);
61
62 st.fun("process:try_wait", |env: &mut Env, _argc: usize| {
63 let mut chld = env.arg(0);
64 chld.with_usr_ref(|vts: &mut VChildProcess| {
65 match vts.child.borrow_mut().try_wait() {
66 Ok(Some(st)) => {
67 let ret = VVal::map();
68 ret.set_key_str("status", VVal::Int(st.code().unwrap_or(-1) as i64))
69 .expect("single use");
70 ret.set_key_str("success", VVal::Bol(st.success()))
71 .expect("single use");
72 Ok(ret)
73 },
74 Ok(None) => Ok(VVal::None),
75 Err(e) => {
76 Ok(env.new_err(
77 format!("Error try_wait pid={}: {}",
78 vts.id, e)))
79 }
80 }
81 }).unwrap_or_else(||
82 Ok(env.new_err(format!(
83 "std:process:try_wait: First argument not an IO handle! {}",
84 chld.s()))))
85 }, Some(1), Some(1), false);
86
87 st.fun("process:wait", |env: &mut Env, _argc: usize| {
88 let mut chld = env.arg(0);
89 chld.with_usr_ref(|vts: &mut VChildProcess| {
90 match vts.child.borrow_mut().wait() {
91 Ok(st) => {
92 let ret = VVal::map();
93 ret.set_key_str("status", VVal::Int(st.code().unwrap_or(-1) as i64))
94 .expect("single use");
95 ret.set_key_str("success", VVal::Bol(st.success()))
96 .expect("single use");
97 Ok(ret)
98 },
99 Err(e) => {
100 Ok(env.new_err(
101 format!("Error wait pid={}: {}",
102 vts.id, e)))
103 }
104 }
105 }).unwrap_or_else(||
106 Ok(env.new_err(format!(
107 "std:process:wait: First argument not an IO handle! {}",
108 chld.s()))))
109 }, Some(1), Some(1), false);
110
111 st.fun("process:kill_wait", |env: &mut Env, _argc: usize| {
112 let mut chld = env.arg(0);
113 chld.with_usr_ref(|vts: &mut VChildProcess| {
114 let kill_res = vts.child.borrow_mut().kill();
115 match kill_res {
116 Ok(_) => {
117 match vts.child.borrow_mut().wait() {
118 Ok(st) => {
119 let ret = VVal::map();
120 ret.set_key_str("status", VVal::Int(st.code().unwrap_or(-1) as i64))
121 .expect("single use");
122 ret.set_key_str("success", VVal::Bol(st.success()))
123 .expect("single use");
124 Ok(ret)
125 },
126 Err(e) => {
127 Ok(env.new_err(
128 format!("Error killing & wait pid={}: {}",
129 vts.id, e)))
130 }
131 }
132 },
133 Err(e) =>
134 Ok(env.new_err(
135 format!("Error killing pid={}: {}",
136 vts.id, e))),
137 }
138 }).unwrap_or_else(||
139 Ok(env.new_err(format!(
140 "std:process:kill_wait: First argument not an IO handle! {}",
141 chld.s()))))
142 }, Some(1), Some(1), false);
143
144 st.fun("process:run", |env: &mut Env, argc: usize| {
145 let cmd_exe = env.arg(0).deref();
146
147 let mut cmd =
148 cmd_exe.with_s_ref(|s| Command::new(s));
149
150 if argc > 1 {
151 let args = env.arg(1).deref();
152 for a in args.iter() {
153 a.0.with_s_ref(|s| cmd.arg(s));
154 }
155 }
156
157 cmd.stdin(Stdio::null());
158
159 match cmd.output() {
160 Ok(out) => {
161 let ret = VVal::map();
162 ret.set_key_str("status", VVal::Int(out.status.code().unwrap_or(-1) as i64))
163 .expect("single use");
164 ret.set_key_str("success", VVal::Bol(out.status.success()))
165 .expect("single use");
166 ret.set_key_str("stdout", VVal::new_byt(out.stdout))
167 .expect("single use");
168 ret.set_key_str("stderr", VVal::new_byt(out.stderr))
169 .expect("single use");
170
171 Ok(ret)
172 },
173 Err(e) => {
174 return Ok(env.new_err(
175 format!("Error executing '{}': {}", cmd_exe.s(), e)));
176 },
177 }
178
179 }, Some(1), Some(2), false);
180}