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 mut split = command.split(" ").collect::<Vec<&str>>();
let mut envs = vec![];
while split[0].contains("=") {
let split1 = split[0].split("=").collect::<Vec<&str>>();
let key = split1[0].trim();
let value = split1[1].trim();
envs.push((key, value));
split = split.iter().skip(1).map(|r| *r).collect::<Vec<&str>>();
}
let args = split
.iter()
.skip(1)
.map(|r| {
if r.starts_with("\"") && r.ends_with("\"") {
let x = &r[1..r.len() - 1];
return x;
}
*r
})
.collect::<Vec<&str>>();
let args = args.as_slice();
let mut child = Command::new(split[0]);
for (key, value) in envs {
child.env(key, value);
}
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);
}
#[tokio::test]
async fn test_command1() {
let result = execute_async(
"DOCKER_BUILDKIT=0 podman --help",
Some("/Users/wangbin/src/docs/docs-taiwu"),
|line| {
println!("stdout:{line}");
},
|line| {
println!("stdout:{line}");
},
|| {
println!("complete");
},
)
.await
.unwrap();
println!("result:{}", result);
}
#[tokio::test]
async fn test_command2() {
let result = execute_async(
"DOCKER_BUILDKIT=0 podman ps \"--help\"",
Some("/Users/wangbin/src/docs/docs-taiwu"),
|line| {
println!("stdout:{line}");
},
|line| {
println!("stdout:{line}");
},
|| {
println!("complete");
},
)
.await
.unwrap();
println!("result:{}", result);
}
#[test]
fn test_slice() {
let a = "\"--help\"";
println!("a:{a}");
let x = &a[1..a.len() - 1];
println!("x:{x}");
}
}