1use crate::node_sys::*;
2use crate::require;
3use js_sys::{Array, Object};
4use lazy_static::lazy_static;
5use wasm_bindgen::prelude::*;
6use workflow_log::log_info;
7
8lazy_static! {
9 static ref CP: Cp = require("child_process").unchecked_into();
10}
11
12#[wasm_bindgen]
13extern "C" {
14
15 #[wasm_bindgen(extends = Object)]
18 #[derive(Clone)]
19 pub type Cp;
20
21 #[wasm_bindgen(js_name = spawn, method)]
24 pub fn cp_spawn(this: &Cp, cmd: &str) -> ChildProcess;
25
26 #[wasm_bindgen(js_name = spawn, method)]
29 pub fn cp_spawn_with_args(this: &Cp, cmd: &str, args: &SpawnArgs) -> ChildProcess;
30
31 #[wasm_bindgen(js_name = spawn, method)]
34 pub fn cp_spawn_with_args_and_options(
35 this: &Cp,
36 cmd: &str,
37 args: &SpawnArgs,
38 options: &SpawnOptions,
39 ) -> ChildProcess;
40
41 #[wasm_bindgen(extends = Array, js_namespace = child_process)]
43 #[derive(Debug, Clone, PartialEq)]
44 pub type SpawnArgs;
45
46 #[wasm_bindgen(extends = Object, js_namespace = child_process)]
48 #[derive(Debug, Clone, PartialEq)]
49 pub type SpawnOptions;
50
51 #[wasm_bindgen(extends = EventEmitter, js_namespace = child_process)]
54 #[derive(Clone, Debug)]
55 pub type ChildProcess;
56
57 #[wasm_bindgen(method, getter)]
59 pub fn exit_code(this: &ChildProcess) -> u64;
60
61 #[wasm_bindgen(method, getter)]
63 pub fn pid(this: &ChildProcess) -> u64;
64
65 #[wasm_bindgen(method, getter)]
67 pub fn stdout(this: &ChildProcess) -> ReadableStream;
68
69 #[wasm_bindgen(method, getter)]
71 pub fn stderr(this: &ChildProcess) -> ReadableStream;
72
73 #[wasm_bindgen(method, getter)]
75 pub fn stdin(this: &ChildProcess) -> WritableStream;
76
77 #[wasm_bindgen(method)]
80 pub fn kill(this: &ChildProcess) -> bool;
81
82 #[wasm_bindgen(method, js_name=kill)]
83 fn kill_with_signal_impl(this: &ChildProcess, signal: JsValue) -> bool;
84}
85
86unsafe impl Send for Cp {}
87unsafe impl Sync for Cp {}
88
89unsafe impl Send for ChildProcess {}
90unsafe impl Sync for ChildProcess {}
91
92unsafe impl Send for SpawnOptions {}
93unsafe impl Sync for SpawnOptions {}
94
95unsafe impl Send for SpawnArgs {}
96unsafe impl Sync for SpawnArgs {}
97
98#[inline(always)]
101pub fn spawn(cmd: &str) -> ChildProcess {
102 CP.cp_spawn(cmd)
103}
104
105#[inline(always)]
108pub fn spawn_with_args(cmd: &str, args: &SpawnArgs) -> ChildProcess {
109 CP.cp_spawn_with_args(cmd, args)
110}
111
112#[inline(always)]
115pub fn spawn_with_args_and_options(
116 cmd: &str,
117 args: &SpawnArgs,
118 options: &SpawnOptions,
119) -> ChildProcess {
120 CP.cp_spawn_with_args_and_options(cmd, args, options)
121}
122
123#[derive(Debug)]
126pub enum KillSignal<'s> {
127 None,
129 SIGKILL,
131 SIGTERM,
133 Message(&'s str),
135 Code(u32),
137}
138
139impl ChildProcess {
140 pub fn kill_with_signal(self: &ChildProcess, signal: KillSignal) -> bool {
143 log_info!("kill_with_signal {:?}", signal);
144 match signal {
145 KillSignal::None => self.kill(),
146 KillSignal::SIGKILL => self.kill_with_signal_impl(JsValue::from("SIGKILL")),
147 KillSignal::SIGTERM => self.kill_with_signal_impl(JsValue::from("SIGTERM")),
148 KillSignal::Message(str) => self.kill_with_signal_impl(JsValue::from(str)),
149 KillSignal::Code(code) => self.kill_with_signal_impl(JsValue::from(code)),
150 }
151 }
152}
153
154impl From<Vec<&str>> for SpawnArgs {
155 fn from(list: Vec<&str>) -> Self {
156 let array = Array::new();
157 for (index, value) in list.iter().enumerate() {
158 array.set(index as u32, JsValue::from(*value));
159 }
160
161 #[allow(unused_mut)]
162 let mut args: Self = ::wasm_bindgen::JsCast::unchecked_into(array);
163 args
164 }
165}
166
167impl From<&[&str]> for SpawnArgs {
168 fn from(list: &[&str]) -> Self {
169 let array = Array::new();
170 for (index, value) in list.iter().enumerate() {
171 array.set(index as u32, JsValue::from(*value));
172 }
173
174 #[allow(unused_mut)]
175 let mut args: Self = ::wasm_bindgen::JsCast::unchecked_into(array);
176 args
177 }
178}
179
180impl From<&[String]> for SpawnArgs {
181 fn from(list: &[String]) -> Self {
182 let array = Array::new();
183 for (index, value) in list.iter().enumerate() {
184 array.set(index as u32, JsValue::from(value));
185 }
186
187 #[allow(unused_mut)]
188 let mut args: Self = ::wasm_bindgen::JsCast::unchecked_into(array);
189 args
190 }
191}
192
193impl Default for SpawnOptions {
194 fn default() -> Self {
195 Self::new()
196 }
197}
198
199impl SpawnOptions {
200 pub fn new() -> Self {
204 #[allow(unused_mut)]
205 let mut ret: Self = ::wasm_bindgen::JsCast::unchecked_into(Object::new());
206 ret
207 }
208
209 pub fn set(&self, key: &str, value: JsValue) -> &Self {
212 let r = ::js_sys::Reflect::set(self.as_ref(), &JsValue::from(key), &value);
213 debug_assert!(
214 r.is_ok(),
215 "setting properties should never fail on our dictionary objects"
216 );
217 let _ = r;
218 self
219 }
220
221 pub fn cwd(&self, cwd: &str) -> &Self {
223 self.set("cwd", JsValue::from(cwd))
224 }
225
226 pub fn env(&self, env: ProcessEnv) -> &Self {
228 self.set("env", JsValue::from(env))
229 }
230
231 pub fn argv0(&self, argv0: &str) -> &Self {
233 self.set("argv0", JsValue::from(argv0))
234 }
235
236 pub fn detached(&self, detached: bool) -> &Self {
239 self.set("detached", JsValue::from(detached))
240 }
241
242 pub fn uid(&self, uid: &str) -> &Self {
244 self.set("uid", JsValue::from(uid))
245 }
246
247 pub fn gid(&self, gid: &str) -> &Self {
249 self.set("gid", JsValue::from(gid))
250 }
251
252 pub fn serialization(&self, serialization: &str) -> &Self {
255 self.set("serialization", JsValue::from(serialization))
256 }
257
258 pub fn shell(&self, shell: bool) -> &Self {
261 self.set("shell", JsValue::from(shell))
262 }
263
264 pub fn shell_str(&self, shell: &str) -> &Self {
266 self.set("shell", JsValue::from(shell))
267 }
268
269 pub fn windows_verbatim_arguments(&self, args: bool) -> &Self {
272 self.set("windowsVerbatimArguments", JsValue::from(args))
273 }
274
275 pub fn windows_hide(&self, windows_hide: bool) -> &Self {
278 self.set("windowsHide", JsValue::from(windows_hide))
279 }
280
281 pub fn timeout(&self, timeout: u32) -> &Self {
284 self.set("timeout", JsValue::from(timeout))
285 }
286
287 pub fn kill_signal(&self, signal: u32) -> &Self {
292 self.set("killSignal", JsValue::from(signal))
293 }
294
295 pub fn kill_signal_str(&self, signal: &str) -> &Self {
298 self.set("killSignal", JsValue::from(signal))
299 }
300
301 pub fn stdio(&self, stdio: &str) -> &Self {
304 self.set("stdio", JsValue::from(stdio))
305 }
306
307 pub fn stdio_with_array(&self, array: js_sys::Array) -> &Self {
310 self.set("stdio", array.into())
311 }
312}