fix: set stdio to null when orphan is true (#229)

This commit is contained in:
三咲雅 · Misaki Masa 2023-09-30 20:43:47 +08:00 committed by GitHub
parent d3d3462b5e
commit 5584ba4844
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 36 deletions

View file

@ -15,37 +15,44 @@ impl ShellOpt {
self.piped = true; self.piped = true;
self self
} }
#[inline]
fn stdio(&self) -> Stdio {
if self.orphan {
Stdio::null()
} else if self.piped {
Stdio::piped()
} else {
Stdio::inherit()
}
}
} }
pub fn shell(opt: ShellOpt) -> Result<Child> { pub fn shell(opt: ShellOpt) -> Result<Child> {
#[cfg(not(target_os = "windows"))] #[cfg(unix)]
{ return Ok(
Ok( Command::new("sh")
Command::new("sh") .arg("-c")
.arg("-c") .stdin(opt.stdio())
.arg(opt.cmd) .stdout(opt.stdio())
.arg("") // $0 is the command name .stderr(opt.stdio())
.args(opt.args) .arg(opt.cmd)
.stdin(if opt.piped { Stdio::piped() } else { Stdio::inherit() }) .arg("") // $0 is the command name
.stdout(if opt.piped { Stdio::piped() } else { Stdio::inherit() }) .args(opt.args)
.stderr(if opt.piped { Stdio::piped() } else { Stdio::inherit() }) .kill_on_drop(!opt.orphan)
.kill_on_drop(!opt.orphan) .spawn()?,
.spawn()?, );
)
}
#[cfg(target_os = "windows")] #[cfg(windows)]
{ return Ok(
Ok( Command::new("cmd")
Command::new("cmd") .stdin(opt.stdio())
.arg("/C") .stdout(opt.stdio())
.arg(opt.cmd) .stderr(opt.stdio())
.args(opt.args) .arg("/C")
.stdin(if opt.piped { Stdio::piped() } else { Stdio::inherit() }) .arg(opt.cmd)
.stdout(if opt.piped { Stdio::piped() } else { Stdio::inherit() }) .args(opt.args)
.stderr(if opt.piped { Stdio::piped() } else { Stdio::inherit() }) .kill_on_drop(true)
.kill_on_drop(true) .spawn()?,
.spawn()?, );
)
}
} }

View file

@ -2,7 +2,6 @@ use std::{ffi::OsString, mem};
use anyhow::Result; use anyhow::Result;
use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::{mpsc, oneshot}}; use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::{mpsc, oneshot}};
use tracing::trace;
use crate::{emit, external::{self, ShellOpt}, tasks::TaskOp, BLOCKER}; use crate::{emit, external::{self, ShellOpt}, tasks::TaskOp, BLOCKER};
@ -41,26 +40,37 @@ impl Process {
fn done(&self, id: usize) -> Result<()> { Ok(self.sch.send(TaskOp::Done(id))?) } fn done(&self, id: usize) -> Result<()> { Ok(self.sch.send(TaskOp::Done(id))?) }
pub(crate) async fn open(&self, mut task: ProcessOpOpen) -> Result<()> { pub(crate) async fn open(&self, mut task: ProcessOpOpen) -> Result<()> {
let opt = ShellOpt::from(&mut task);
if task.block { if task.block {
let _guard = BLOCKER.acquire().await.unwrap(); let _guard = BLOCKER.acquire().await.unwrap();
emit!(Stop(true)).await; emit!(Stop(true)).await;
match external::shell(ShellOpt::from(&mut task)) { match external::shell(opt) {
Ok(mut child) => { Ok(mut child) => {
child.wait().await.ok(); child.wait().await.ok();
self.done(task.id)?;
} }
Err(e) => { Err(e) => {
trace!("Failed to spawn process: {e}"); self.sch.send(TaskOp::New(task.id, 0))?;
self.log(task.id, format!("Failed to spawn process: {e}"))?;
} }
} }
emit!(Stop(false)).await; return Ok(emit!(Stop(false)).await);
}
self.sch.send(TaskOp::Adv(task.id, 1, 0))?; if task.orphan {
return self.done(task.id); match external::shell(opt) {
Ok(_) => self.done(task.id)?,
Err(e) => {
self.sch.send(TaskOp::New(task.id, 0))?;
self.log(task.id, format!("Failed to spawn process: {e}"))?;
}
}
return Ok(());
} }
self.sch.send(TaskOp::New(task.id, 0))?; self.sch.send(TaskOp::New(task.id, 0))?;
let mut child = external::shell(ShellOpt::from(&mut task).with_piped())?; let mut child = external::shell(opt.with_piped())?;
let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines(); let mut stdout = BufReader::new(child.stdout.take().unwrap()).lines();
let mut stderr = BufReader::new(child.stderr.take().unwrap()).lines(); let mut stderr = BufReader::new(child.stderr.take().unwrap()).lines();