82 lines · 2.2 KB · Rust
RawDownload
use anyhow::{Context as _, Result};use std::process::Stdio; /// A wrapper around `smol::process::Child` that ensures all subprocesses/// are killed when the process is terminated by using process groups.pub struct Child {    process: smol::process::Child,} impl std::ops::Deref for Child {    type Target = smol::process::Child;     fn deref(&self) -> &Self::Target {        &self.process    }} impl std::ops::DerefMut for Child {    fn deref_mut(&mut self) -> &mut Self::Target {        &mut self.process    }} impl Child {    #[cfg(not(windows))]    pub fn spawn(        mut command: std::process::Command,        stdin: Stdio,        stdout: Stdio,        stderr: Stdio,    ) -> Result<Self> {        crate::set_pre_exec_to_start_new_session(&mut command);        let mut command = smol::process::Command::from(command);        let process = command            .stdin(stdin)            .stdout(stdout)            .stderr(stderr)            .spawn()            .with_context(|| format!("failed to spawn command {command:?}"))?;        Ok(Self { process })    }     #[cfg(windows)]    pub fn spawn(        command: std::process::Command,        stdin: Stdio,        stdout: Stdio,        stderr: Stdio,    ) -> Result<Self> {        // TODO(windows): create a job object and add the child process handle to it,        // see https://learn.microsoft.com/en-us/windows/win32/procthread/job-objects        let mut command = smol::process::Command::from(command);        let process = command            .stdin(stdin)            .stdout(stdout)            .stderr(stderr)            .spawn()            .with_context(|| format!("failed to spawn command {command:?}"))?;         Ok(Self { process })    }     pub fn into_inner(self) -> smol::process::Child {        self.process    }     #[cfg(not(windows))]    pub fn kill(&mut self) -> Result<()> {        let pid = self.process.id();        unsafe {            libc::killpg(pid as i32, libc::SIGKILL);        }        Ok(())    }     #[cfg(windows)]    pub fn kill(&mut self) -> Result<()> {        // TODO(windows): terminate the job object in kill        self.process.kill()?;        Ok(())    }}