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