use std::path::Path;
use std::process::Command;
use anyhow::{Context, Result};
#[cfg(windows)]
use std::ffi::OsString;
#[cfg(windows)]
use std::process::Stdio;
#[cfg(windows)]
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
#[cfg(windows)]
const DETACHED_PROCESS: u32 = 0x0000_0008;
pub fn spawn_detached(cmd: &mut Command, gui: bool, _file_for_log: &Path) -> Result<()> {
#[cfg(windows)]
{
if gui {
return spawn_detached_gui_windows(cmd);
}
spawn_detached_console_windows(cmd)
}
#[cfg(not(windows))]
{
let _ = gui;
cmd.spawn().context("spawn failed")?;
Ok(())
}
}
#[cfg(windows)]
fn spawn_detached_gui_windows(cmd: &mut Command) -> Result<()> {
use std::os::windows::process::CommandExt;
cmd.creation_flags(CREATE_NO_WINDOW | DETACHED_PROCESS)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null());
cmd.spawn()
.context("spawn detached GUI (CREATE_NO_WINDOW) failed")?;
Ok(())
}
#[cfg(windows)]
fn spawn_detached_console_windows(cmd: &mut Command) -> Result<()> {
let program = cmd.get_program().to_os_string();
let args: Vec<OsString> = cmd.get_args().map(|s| s.to_os_string()).collect();
let cwd = cmd.get_current_dir().map(|p| p.to_path_buf());
let envs: Vec<(OsString, Option<OsString>)> = cmd
.get_envs()
.map(|(k, v)| (k.to_os_string(), v.map(|s| s.to_os_string())))
.collect();
let mut wrapper = Command::new("cmd");
wrapper.arg("/c").arg("start").arg("");
wrapper.arg(&program);
for a in &args {
wrapper.arg(a);
}
if let Some(d) = cwd {
wrapper.current_dir(d);
}
for (k, v) in envs {
match v {
Some(v) => {
wrapper.env(&k, v);
}
None => {
wrapper.env_remove(&k);
}
}
}
wrapper.spawn().context("spawn via cmd /c start failed")?;
Ok(())
}
pub fn is_windows() -> bool {
cfg!(target_os = "windows")
}
pub fn is_linux() -> bool {
cfg!(target_os = "linux")
}
pub fn is_mac() -> bool {
cfg!(target_os = "macos")
}