1 use std::process::Command; 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 spawn(&self) -> Result<(), RuntimeError>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 /// ## 阻塞式运行 no_spawn(&self) -> Result<(), RuntimeError>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 .spawn(); 47 48 match result { 49 Ok(mut child) => match child.wait() { 50 Ok(status) => { 51 if !status.success() && !self.ignore { 52 return Err(RuntimeError::new(RuntimeErrorType::ExecFailed)); 53 } 54 } 55 Err(_) => { 56 if !self.ignore { 57 return Err(RuntimeError::new(RuntimeErrorType::ExecFailed)); 58 } 59 } 60 }, 61 Err(e) => { 62 if !self.ignore { 63 eprintln!("{}: Command failed: {}", self.path, e); 64 return Err(RuntimeError::new(RuntimeErrorType::ExecFailed)); 65 } 66 } 67 } 68 Ok(()) 69 } 70 71 /// ## 若这个cmd任务spawn了,则kill这个cmd进程 stop(&mut self)72 pub fn stop(&mut self) { 73 if self.pid != 0 { 74 let res = UnitManager::pop_cmd_proc(self.pid).unwrap(); 75 76 let mut proc = res.lock().unwrap(); 77 78 match proc.try_wait() { 79 //进程正常退出 80 Ok(Some(_status)) => {} 81 //进程错误退出(或启动失败) 82 _ => { 83 proc.kill().expect("Cannot kill cmd task"); 84 } 85 }; 86 } 87 } 88 } 89