wang_utils/command/
mod.rspub async fn execute_async(
command: &str,
folder: Option<&str>,
stdout_fn: impl Fn(String) + Send + Sync + 'static,
stderr_fn: impl Fn(String) + Send + Sync + 'static,
complete_fn: impl Fn() + Send + Sync + 'static,
) -> anyhow::Result<bool> {
use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
std::env::set_var("IS_TTY", "true");
let split = command.split(" ").collect::<Vec<&str>>();
let args = split.iter().skip(1).map(|r| *r).collect::<Vec<&str>>();
let args = args.as_slice();
let mut child = Command::new(split[0]);
let child = child.args(args);
let child = if folder.is_some() {
let folder = folder.unwrap();
child.current_dir(folder)
} else {
child
};
let child = child
.stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn();
if child.is_err() {
let error = child.err().unwrap();
stderr_fn(error.to_string());
return Ok(false);
}
let mut child = child?;
let stdout = child.stdout.take().unwrap();
let stderr = child.stderr.take().unwrap();
let handle1 = tokio::spawn(async move {
let reader = BufReader::new(stdout);
for line in reader.lines() {
if let Ok(line) = line {
stdout_fn(line);
}
}
});
let handle2 = tokio::spawn(async move {
let reader = BufReader::new(stderr);
for line in reader.lines() {
if let Ok(line) = line {
stderr_fn(line);
}
}
});
tokio::try_join!(handle1, handle2)?;
let status = child.wait()?;
if status.success() {
complete_fn();
Ok(true)
} else {
Ok(false)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_command() {
let command = "pwd";
let result = execute_async(
command,
Some("/Users/wangbin/src/docs/docs-taiwu"),
|line| {
println!("stdout:{line}");
},
|line| {
println!("stdout:{line}");
},
|| {
println!("complete");
},
)
.await
.unwrap();
println!("result:{}", result);
}
}