1use crate::require;
2use js_sys::{Array, Object};
3use lazy_static::lazy_static;
4use node_sys::*;
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)]
16 #[derive(Clone)]
17 pub type Cp;
18
19 #[wasm_bindgen(js_name = spawn, method)]
20 pub fn cp_spawn(this: &Cp, cmd: &str) -> ChildProcess;
21
22 #[wasm_bindgen(js_name = spawn, method)]
23 pub fn cp_spawn_with_args(this: &Cp, cmd: &str, args: &SpawnArgs) -> ChildProcess;
24
25 #[wasm_bindgen(js_name = spawn, method)]
26 pub fn cp_spawn_with_args_and_options(
27 this: &Cp,
28 cmd: &str,
29 args: &SpawnArgs,
30 options: &SpawnOptions,
31 ) -> ChildProcess;
32
33 #[wasm_bindgen(extends = Array, js_namespace = child_process)]
34 #[derive(Debug, Clone, PartialEq, Eq)]
35 pub type SpawnArgs;
36
37 #[wasm_bindgen(extends = Object, js_namespace = child_process)]
38 #[derive(Debug, Clone, PartialEq, Eq)]
39 pub type SpawnOptions;
40
41 #[wasm_bindgen(extends = EventEmitter, js_namespace = child_process)]
42 #[derive(Clone, Debug)]
43 pub type ChildProcess;
44
45 #[wasm_bindgen(method, getter)]
46 pub fn exit_code(this: &ChildProcess) -> u64;
47
48 #[wasm_bindgen(method, getter)]
49 pub fn pid(this: &ChildProcess) -> u64;
50
51 #[wasm_bindgen(method, getter)]
52 pub fn stdout(this: &ChildProcess) -> ReadableStream;
53
54 #[wasm_bindgen(method, getter)]
55 pub fn stderr(this: &ChildProcess) -> ReadableStream;
56
57 #[wasm_bindgen(method, getter)]
58 pub fn stdin(this: &ChildProcess) -> WritableStream;
59
60 #[wasm_bindgen(method)]
61 pub fn kill(this: &ChildProcess) -> bool;
62
63 #[wasm_bindgen(method, js_name=kill)]
64 fn kill_with_signal_impl(this: &ChildProcess, signal: JsValue) -> bool;
65}
66
67unsafe impl Send for Cp {}
68unsafe impl Sync for Cp {}
69
70unsafe impl Send for ChildProcess {}
71unsafe impl Sync for ChildProcess {}
72
73unsafe impl Send for SpawnOptions {}
74unsafe impl Sync for SpawnOptions {}
75
76unsafe impl Send for SpawnArgs {}
77unsafe impl Sync for SpawnArgs {}
78
79#[inline(always)]
80pub fn spawn(cmd: &str) -> ChildProcess {
81 CP.cp_spawn(cmd)
82}
83
84#[inline(always)]
85pub fn spawn_with_args(cmd: &str, args: &SpawnArgs) -> ChildProcess {
86 CP.cp_spawn_with_args(cmd, args)
87}
88
89#[inline(always)]
90pub fn spawn_with_args_and_options(
91 cmd: &str,
92 args: &SpawnArgs,
93 options: &SpawnOptions,
94) -> ChildProcess {
95 CP.cp_spawn_with_args_and_options(cmd, args, options)
96}
97
98#[derive(Debug)]
99pub enum KillSignal<'s> {
100 None,
101 SIGKILL,
102 SIGTERM,
103 Message(&'s str),
104 Code(u32),
105}
106
107impl ChildProcess {
108 pub fn kill_with_signal(self: &ChildProcess, signal: KillSignal) -> bool {
109 log_info!("kill_with_signal {:?}", signal);
110 match signal {
111 KillSignal::None => self.kill(),
112 KillSignal::SIGKILL => self.kill_with_signal_impl(JsValue::from("SIGKILL")),
113 KillSignal::SIGTERM => self.kill_with_signal_impl(JsValue::from("SIGTERM")),
114 KillSignal::Message(str) => self.kill_with_signal_impl(JsValue::from(str)),
115 KillSignal::Code(code) => self.kill_with_signal_impl(JsValue::from(code)),
116 }
117 }
118}
119
120impl From<Vec<&str>> for SpawnArgs {
121 fn from(list: Vec<&str>) -> Self {
122 let array = Array::new();
123 for (index, value) in list.iter().enumerate() {
124 array.set(index as u32, JsValue::from(*value));
125 }
126
127 #[allow(unused_mut)]
128 let mut args: Self = ::wasm_bindgen::JsCast::unchecked_into(array);
129 args
130 }
131}
132
133impl From<&[&str]> for SpawnArgs {
134 fn from(list: &[&str]) -> Self {
135 let array = Array::new();
136 for (index, value) in list.iter().enumerate() {
137 array.set(index as u32, JsValue::from(*value));
138 }
139
140 #[allow(unused_mut)]
141 let mut args: Self = ::wasm_bindgen::JsCast::unchecked_into(array);
142 args
143 }
144}
145
146impl From<&[String]> for SpawnArgs {
147 fn from(list: &[String]) -> Self {
148 let array = Array::new();
149 for (index, value) in list.iter().enumerate() {
150 array.set(index as u32, JsValue::from(value));
151 }
152
153 #[allow(unused_mut)]
154 let mut args: Self = ::wasm_bindgen::JsCast::unchecked_into(array);
155 args
156 }
157}
158
159impl Default for SpawnOptions {
160 fn default() -> Self {
161 Self::new()
162 }
163}
164
165impl SpawnOptions {
166 pub fn new() -> Self {
170 #[allow(unused_mut)]
171 let mut ret: Self = ::wasm_bindgen::JsCast::unchecked_into(Object::new());
172 ret
173 }
174
175 pub fn set(&self, key: &str, value: JsValue) -> &Self {
176 let r = ::js_sys::Reflect::set(self.as_ref(), &JsValue::from(key), &value);
177 debug_assert!(
178 r.is_ok(),
179 "setting properties should never fail on our dictionary objects"
180 );
181 let _ = r;
182 self
183 }
184
185 pub fn cwd(&self, cwd: &str) -> &Self {
186 self.set("cwd", JsValue::from(cwd))
187 }
188
189 pub fn env(&self, env: ProcessEnv) -> &Self {
190 self.set("env", JsValue::from(env))
191 }
192
193 pub fn argv0(&self, argv0: &str) -> &Self {
194 self.set("argv0", JsValue::from(argv0))
195 }
196
197 pub fn detached(&self, detached: bool) -> &Self {
198 self.set("detached", JsValue::from(detached))
199 }
200
201 pub fn uid(&self, uid: &str) -> &Self {
202 self.set("uid", JsValue::from(uid))
203 }
204
205 pub fn gid(&self, gid: &str) -> &Self {
206 self.set("gid", JsValue::from(gid))
207 }
208
209 pub fn serialization(&self, serialization: &str) -> &Self {
210 self.set("serialization", JsValue::from(serialization))
211 }
212
213 pub fn shell(&self, shell: bool) -> &Self {
214 self.set("shell", JsValue::from(shell))
215 }
216
217 pub fn shell_str(&self, shell: &str) -> &Self {
218 self.set("shell", JsValue::from(shell))
219 }
220
221 pub fn windows_verbatim_arguments(&self, args: bool) -> &Self {
222 self.set("windowsVerbatimArguments", JsValue::from(args))
223 }
224
225 pub fn windows_hide(&self, windows_hide: bool) -> &Self {
226 self.set("windowsHide", JsValue::from(windows_hide))
227 }
228
229 pub fn timeout(&self, timeout: u32) -> &Self {
230 self.set("timeout", JsValue::from(timeout))
231 }
232
233 pub fn kill_signal(&self, signal: u32) -> &Self {
236 self.set("killSignal", JsValue::from(signal))
237 }
238
239 pub fn kill_signal_str(&self, signal: &str) -> &Self {
240 self.set("killSignal", JsValue::from(signal))
241 }
242
243 pub fn stdio(&self, stdio: &str) -> &Self {
244 self.set("stdio", JsValue::from(stdio))
245 }
246
247 pub fn stdio_with_array(&self, array: js_sys::Array) -> &Self {
248 self.set("stdio", array.into())
249 }
250}