awesome_operates/helper/
execute.rs

1use std::process::{Output, Stdio};
2
3use cfg_if::cfg_if;
4use serde::Serialize;
5use tokio::io::{AsyncBufReadExt, BufReader};
6use tokio::process::Command;
7use tokio::sync::mpsc::Sender;
8
9pub async fn execute_command(cmd: &str) -> anyhow::Result<Output> {
10    tracing::info!("execute command `{cmd}`");
11    Ok(Command::new("sh").args(["-c", cmd]).output().await?)
12}
13
14pub async fn execute_command_with_args_sender(cmd: &str, args: Vec<String>, tx: Sender<String>) {
15    tracing::info!("execute command `{cmd}` with args: `{args:?}`");
16    let mut child = Command::new(cmd)
17        .args(args)
18        .stdout(Stdio::piped())
19        .spawn()
20        .expect("fail to execute");
21
22    let stdout = child
23        .stdout
24        .take()
25        .expect("child did not have a handle to stdout");
26    let mut reader = BufReader::new(stdout).lines();
27
28    tokio::spawn(async move {
29        let status = child
30            .wait()
31            .await
32            .expect("child process encountered an error");
33
34        tracing::info!("child status was: {status}");
35    });
36
37    while let Some(line) = reader
38        .next_line()
39        .await
40        .unwrap_or(Some("fail to get output".to_owned()))
41    {
42        tx.send(line).await.unwrap();
43    }
44}
45
46/// ```rust
47/// use awesome_operates::helper::kill_process_by_pid;
48/// # async {
49/// #     kill_process_by_pid(999990).await;
50/// #     kill_process_by_pid(Some(99999999)).await;
51/// #     // this will has no use
52/// #     kill_process_by_pid(None::<u32>).await;
53/// # };
54/// ```
55pub async fn kill_process_by_pid<T>(pid: T)
56where
57    T: Serialize,
58{
59    let value = serde_json::json!(pid);
60    if value.as_u64().is_none() {
61        return;
62    }
63    let pid = value.to_string();
64    let pid_str = pid.as_str();
65    cfg_if! {
66        if #[cfg(unix)] {
67           let status = tokio::process::Command::new("kill")
68            .args(["-9", pid_str])
69            .status()
70            .await
71            .unwrap();
72        } else {
73            let status = tokio::process::Command::new("taskkill")
74                .args([r"/T", r"/F", r"/PID", pid_str])
75                .status()
76                .await
77                .unwrap();
78        }
79    }
80    tracing::info!("kill process {pid_str} with exit status {status:?}");
81}