xref: /DragonReach/src/task/cmdtask/mod.rs (revision ea330323f68db57353801959d67cbd8e0031aa18)
1 use std::{eprint, eprintln, print, process::Command, string::String, vec::Vec};
2 
3 use crate::{
4     error::runtime_error::{RuntimeError, RuntimeErrorType},
5     manager::UnitManager,
6 };
7 
8 #[derive(Debug, Clone, Default)]
9 pub struct CmdTask {
10     pub path: String,
11     pub cmd: Vec<String>,
12     pub ignore: bool, //表示忽略这个命令的错误,即使它运行失败也不影响unit正常运作
13     pub dir: String,
14     pub envs: Vec<(String, String)>,
15     pub pid: u32,
16 }
17 
18 impl CmdTask {
19     /// ## 以新建进程的方式运行这个cmd
20     pub fn spawn(&self) -> Result<(), RuntimeError> {
21         let result = Command::new(&self.path)
22             .args(&self.cmd)
23             .current_dir(self.dir.clone())
24             .envs(self.envs.clone())
25             .spawn();
26         match result {
27             Ok(proc) => {
28                 UnitManager::push_cmd_proc(proc);
29             }
30             Err(err) => {
31                 if !self.ignore {
32                     eprintln!("{}: Command failed: {}", self.path, err);
33                     return Err(RuntimeError::new(RuntimeErrorType::ExecFailed));
34                 }
35             }
36         }
37         Ok(())
38     }
39 
40     /// ## 阻塞式运行
41     pub fn no_spawn(&self) -> Result<(), RuntimeError> {
42         let result = Command::new(&self.path)
43             .args(&self.cmd)
44             .current_dir(self.dir.clone())
45             .envs(self.envs.clone())
46             .output();
47         match result {
48             Ok(output) => {
49                 print!("{}", String::from_utf8_lossy(&output.stdout));
50                 eprint!("{}", String::from_utf8_lossy(&output.stderr));
51                 if !output.status.success() {
52                     return Err(RuntimeError::new(RuntimeErrorType::ExecFailed));
53                 }
54             }
55             Err(err) => {
56                 if !self.ignore {
57                     eprintln!("{}: Command failed: {}", self.path, err);
58                     return Err(RuntimeError::new(RuntimeErrorType::ExecFailed));
59                 }
60             }
61         }
62         Ok(())
63     }
64 
65     /// ## 若这个cmd任务spawn了,则kill这个cmd进程
66     pub fn stop(&mut self) {
67         if self.pid != 0 {
68             let res = UnitManager::pop_cmd_proc(self.pid).unwrap();
69 
70             let mut proc = res.lock().unwrap();
71 
72             match proc.try_wait() {
73                 //进程正常退出
74                 Ok(Some(_status)) => {}
75                 //进程错误退出(或启动失败)
76                 _ => {
77                     proc.kill().expect("Cannot kill cmd task");
78                 }
79             };
80         }
81     }
82 }
83