use std::path::Path;
use std::process::Stdio;
use crate::stream_process::{ChildEnv, StreamingCommand};
use crate::trace::trace_lazy;
use crate::Result;
#[cfg(windows)]
const CREATE_NEW_PROCESS_GROUP: u32 = 0x0000_0200;
#[cfg(windows)]
const DETACHED_PROCESS: u32 = 0x0000_0008;
pub(crate) fn spawn_detached(
command: &StreamingCommand,
cwd: Option<&Path>,
env: &ChildEnv,
) -> Result<Option<u32>> {
let mut cmd = command.command(env.vars.as_ref()).into_std();
cmd.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null());
if let Some(cwd) = cwd {
cmd.current_dir(cwd);
}
env.apply(&mut cmd);
#[cfg(unix)]
{
use std::os::unix::process::CommandExt;
cmd.process_group(0);
}
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
cmd.creation_flags(CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS);
}
let mut child = cmd.spawn()?;
let pid = child.id();
trace_lazy("detach", || format!("Spawned detached child | pid={pid}"));
let _ = std::thread::Builder::new()
.name("command-stream-detached".to_string())
.spawn(move || {
let _ = child.wait();
});
Ok(Some(pid))
}
impl crate::ProcessRunner {
pub fn spawn_detached(&self) -> Result<Option<u32>> {
let options = self.options();
let runner = match &self.argv {
Some(argv) => crate::StreamingRunner::with_command(argv.clone()),
None => crate::StreamingRunner::new(self.command()),
};
let mut runner = runner
.prefer_local(options.prefer_local.clone())
.env_remove_all(options.env_remove.iter().cloned());
if let Some(cwd) = crate::resolve_spawn_cwd(options.cwd.as_ref()) {
runner = runner.cwd(cwd);
}
if let Some(env) = &options.env {
runner = runner.env(env.clone());
}
runner.detach()
}
}