launcher/
spawn_process.rs1use std::process::{Command, Stdio};
16use common::logging::LogLevel::Info;
17use common::r_log;
18
19pub fn spawn_process(bin_name: &str, args: &[&str], show_console: bool) -> std::io::Result<std::process::Child> {
51 let exe_dir = std::env::current_exe()?
52 .parent()
53 .map(|p| p.to_path_buf())
54 .unwrap_or_else(|| std::path::PathBuf::from("."));
55
56 #[cfg(target_os = "windows")]
57 let target_exe = if exe_dir.join(format!("{}.exe", bin_name)).exists() {
58 exe_dir.join(format!("{}.exe", bin_name))
59 } else {
60 exe_dir.join(bin_name)
61 };
62
63 #[cfg(not(target_os = "windows"))]
64 let target_exe = exe_dir.join(bin_name);
65
66 #[cfg(target_os = "windows")]
67 {
68 spawn_windows(bin_name, &target_exe, &exe_dir, args, show_console)
69 }
70 #[cfg(target_os = "linux")]
71 {
72 spawn_linux(bin_name, &target_exe, &exe_dir, args, show_console)
73 }
74 #[cfg(target_os = "macos")]
75 {
76 spawn_macos(bin_name, &target_exe, &exe_dir, args, show_console)
77 }
78 #[cfg(not(any(target_os = "windows", target_os = "linux", target_os = "macos")))]
79 {
80 let mut cmd = Command::new(&target_exe);
81 cmd.args(args).current_dir(&exe_dir);
82 #[cfg(unix)]
83 {
84 use std::os::unix::process::CommandExt;
85 cmd.process_group(0);
86 }
87 cmd.spawn()
88 }
89}
90
91pub fn spawn_kernel(args: &[&str], show_console: bool) -> std::io::Result<std::process::Child> {
109 spawn_process("rektal_kernel", args, show_console)
110}
111
112pub fn spawn_gui(args: &[&str], show_console: bool) -> std::io::Result<std::process::Child> {
130 spawn_process("rektal_client", args, show_console)
131}
132
133#[cfg(target_os = "windows")]
135fn spawn_windows(
136 _bin_name: &str,
137 target_exe: &std::path::Path,
138 cwd: &std::path::Path,
139 args: &[&str],
140 show_console: bool,
141) -> std::io::Result<std::process::Child> {
142 use std::os::windows::process::CommandExt;
143 const CREATE_NEW_CONSOLE: u32 = 0x00000010;
144 const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
145
146 let mut cmd = Command::new(target_exe);
147 cmd.args(args).current_dir(cwd);
148
149 if show_console {
150 cmd.creation_flags(CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP);
151 } else {
152 cmd.creation_flags(CREATE_NEW_PROCESS_GROUP);
153 }
154
155 cmd.spawn()
156}
157
158#[cfg(target_os = "linux")]
163fn spawn_linux(
164 bin_name: &str,
165 target_exe: &std::path::Path,
166 cwd: &std::path::Path,
167 args: &[&str],
168 show_console: bool,
169) -> std::io::Result<std::process::Child> {
170 use std::os::unix::process::CommandExt;
171
172 if !show_console {
173 let mut cmd = Command::new(target_exe);
174 cmd.args(args)
175 .current_dir(cwd)
176 .stdin(Stdio::null())
177 .stdout(Stdio::null())
178 .stderr(Stdio::null())
179 .process_group(0);
180 return cmd.spawn();
181 }
182
183 let title = format!("REKTAL {}", bin_name.to_uppercase());
184 let formatted_args = args
185 .iter()
186 .map(|a| format!("'{}'", a.replace('\'', "'\\''")))
187 .collect::<Vec<_>>()
188 .join(" ");
189
190 let full_cmd = if formatted_args.is_empty() {
191 format!(
192 "cd '{}' && '{}'; echo ''; read -p '{} terminated. Press Enter to close...' -r",
193 cwd.display(),
194 target_exe.display(),
195 bin_name
196 )
197 } else {
198 format!(
199 "cd '{}' && '{}' {}; echo ''; read -p '{} terminated. Press Enter to close...' -r",
200 cwd.display(),
201 target_exe.display(),
202 formatted_args,
203 bin_name
204 )
205 };
206
207 let mut candidates = Vec::new();
208 if let Ok(user_term) = std::env::var("TERMINAL") {
209 candidates.push(user_term);
210 }
211 candidates.extend([
212 "xdg-terminal-exec".to_string(),
213 "x-terminal-emulator".to_string(),
214 "gnome-terminal".to_string(),
215 "konsole".to_string(),
216 "xterm".to_string(),
217 ]);
218
219 for term in &candidates {
220 let mut cmd = Command::new(term);
221 if term == "xdg-terminal-exec" {
222 cmd.args(["bash", "-c", &full_cmd]);
223 } else if term == "gnome-terminal" {
224 cmd.args(["--title", &title, "--", "bash", "-c", &full_cmd]);
225 } else if term == "konsole" {
226 cmd.args(["-p", &format!("tabtitle={}", title), "-e", "bash", "-c", &full_cmd]);
227 } else {
228 cmd.args(["-e", "bash", "-c", &full_cmd]);
229 }
230
231 cmd.stdin(Stdio::null())
232 .stdout(Stdio::null())
233 .stderr(Stdio::null())
234 .process_group(0);
235
236 if let Ok(child) = cmd.spawn() {
237 return Ok(child);
238 }
239 }
240
241 r_log!(Info, "Could not find terminal-application! running command discretely!");
242 let mut cmd = Command::new(target_exe);
243 cmd.args(args)
244 .current_dir(cwd)
245 .stdin(Stdio::null())
246 .stdout(Stdio::null())
247 .stderr(Stdio::null())
248 .process_group(0);
249 cmd.spawn()
250}
251
252#[cfg(target_os = "macos")]
254fn spawn_macos(
255 bin_name: &str,
256 target_exe: &std::path::Path,
257 cwd: &std::path::Path,
258 args: &[&str],
259 show_console: bool,
260) -> std::io::Result<std::process::Child> {
261 use std::os::unix::process::CommandExt;
262
263 if !show_console {
264 let mut cmd = Command::new(target_exe);
265 cmd.args(args)
266 .current_dir(cwd)
267 .stdin(Stdio::null())
268 .stdout(Stdio::null())
269 .stderr(Stdio::null())
270 .process_group(0);
271 return cmd.spawn();
272 }
273
274 let formatted_args = args
275 .iter()
276 .map(|a| format!("'{}'", a.replace('\'', "'\\''")))
277 .collect::<Vec<_>>()
278 .join(" ");
279
280 let full_cmd = if formatted_args.is_empty() {
281 format!(
282 "cd '{}' && '{}'; echo ''; read -p '{} terminated. Press Enter to close...' -r",
283 cwd.display(),
284 target_exe.display(),
285 bin_name
286 )
287 } else {
288 format!(
289 "cd '{}' && '{}' {}; echo ''; read -p '{} terminated. Press Enter to close...' -r",
290 cwd.display(),
291 target_exe.display(),
292 formatted_args,
293 bin_name
294 )
295 };
296
297 let script = format!(
298 "tell application \"Terminal\" to do script \"{}\"",
299 full_cmd.replace('\\', "\\\\").replace('\"', "\\\"")
300 );
301
302 let mut cmd = Command::new("osascript");
303 cmd.args(["-e", &script])
304 .stdin(Stdio::null())
305 .stdout(Stdio::null())
306 .stderr(Stdio::null())
307 .process_group(0);
308 cmd.spawn()
309}