1
2mod errors;
3#[allow(unused_imports)]
4use extlog::*;
5#[allow(unused_imports)]
6use extlog::loglib::*;
7use std::process::{Command,Stdio,Child,ExitStatus};
8use std::thread::{JoinHandle};
9use std::cell::RefCell;
10use std::sync::Arc;
11use std::error::Error;
12use std::io::{Write};
13
14cmdpack_error_class!{CmdPackError}
15
16pub struct CmdExecInner {
17 cmds :Vec<String>,
18 chld : Vec<Child>,
19 thropt :Vec<JoinHandle<()>>,
20}
21
22impl Drop for CmdExecInner {
23 fn drop(&mut self) {
24 self.close();
25 }
26}
27
28impl CmdExecInner {
29 fn close(&mut self) {
30 while self.chld.len() > 0 {
31 let mut curchld = self.chld.pop().unwrap();
32 loop {
33 let ores = curchld.try_wait();
34 if ores.is_ok() {
35 let ow :Option<ExitStatus> = ores.unwrap();
36 if ow.is_some() {
37 break;
38 }
39 }
40
41 let _ =curchld.kill();
42 }
43 }
44
45 while self.thropt.len() > 0 {
46 let jp = self.thropt.pop().unwrap();
47 let _ = jp.join();
48 }
49 return;
50 }
51
52 pub (crate) fn new(cmds :&[String]) -> Result<Self,Box<dyn Error>> {
53 let mut retv :Self = Self {
54 cmds : Vec::new(),
55 chld : Vec::new(),
56 thropt : Vec::new(),
57 };
58
59 let mut idx :usize = 0;
60 while idx < cmds.len() {
61 retv.cmds.push(format!("{}",cmds[idx]));
62 idx += 1;
63 }
64 Ok(retv)
65 }
66
67 pub (crate) fn new_str(cmds :&[&str]) -> Result<Self,Box<dyn Error>> {
68 let mut retv :Self = Self {
69 cmds : Vec::new(),
70 chld : Vec::new(),
71 thropt : Vec::new(),
72 };
73
74 let mut idx :usize = 0;
75 while idx < cmds.len() {
76 retv.cmds.push(format!("{}",cmds[idx]));
77 idx += 1;
78 }
79 Ok(retv)
80 }
81
82 pub (crate) fn run_bytes(&mut self,inputb :&[u8]) -> Result<(Vec<u8>,Vec<u8>,i32),Box<dyn Error>> {
83 if self.cmds.len() == 0 {
84 cmdpack_new_error!{CmdPackError,"cmds.len == 0"}
85 }
86 if self.chld.len() > 0 {
87 cmdpack_new_error!{CmdPackError,"{:?} still running",self.cmds}
88 }
89 let mut cmd :Command = Command::new(&self.cmds[0]);
90 let mut idx :usize = 1;
91 while idx < self.cmds.len() {
92 cmd.arg(&self.cmds[idx]);
93 idx += 1;
94 }
95
96
97 if inputb.len() == 0{
98 cmd.stdin(Stdio::null());
99 } else {
100 cmd.stdin(Stdio::piped());
101 }
102 cmd.stdout(Stdio::piped());
103 cmd.stderr(Stdio::piped());
104 self.chld.push(cmd.spawn()?);
105 if inputb.len() > 0 {
106 if inputb.len() > 512 {
107 debug_buffer_trace!(inputb.as_ptr(),512,"write out buffer top [512]");
108 debug_buffer_trace!(inputb[(inputb.len()-512)..].as_ptr(),512,"write out buffer end [512]");
109 } else {
110 debug_buffer_trace!(inputb.as_ptr(),inputb.len(),"write out buffer");
111 }
112
113 let cb :Vec<u8> = inputb.to_vec();
114 let mut stdin = self.chld[0].stdin.take().unwrap();
115 self.thropt.push(std::thread::spawn(move || {
116 let mut writed :usize = 0;
117 let mut cursize :usize;
118 loop {
119 if writed >= cb.len() {
120 break;
121 }
122 debug_trace!("writed {}:0x{:x}",writed,writed);
123
124 let ores = stdin.write(&cb[writed..]);
125 if ores.is_err() {
126 break;
127 }
128 cursize = ores.unwrap();
129 debug_trace!("write {}:0x{:x} size",cursize,cursize);
130 writed += cursize;
131 }
132 drop(stdin);
133 }));
134
135 }
137
138
139 let curchld = self.chld.pop().unwrap();
140 let output = curchld.wait_with_output()?;
141 let othr = self.thropt.pop();
142 if othr.is_some() {
143 let thr = othr.unwrap();
144 let _ = thr.join();
145 }
146 let mut exitcode :i32 = -1;
147 let code :Option<i32> = output.status.code();
148 if code.is_some() {
149 exitcode = code.unwrap();
150 }
151 Ok((output.stdout.clone(),output.stderr.clone(),exitcode))
154 }
155
156 pub (crate) fn run(&mut self,inputs :&str) -> Result<(String,String,i32),Box<dyn Error>> {
157 let (outb,errb,exitcode) = self.run_bytes(inputs.as_bytes())?;
158 let mut outs :String = "".to_string();
159 let mut errs :String = "".to_string();
160 if outb.len() > 0 {
161 let ores = std::str::from_utf8(&outb);
162 if ores.is_err() {
163 cmdpack_new_error!{CmdPackError,"can not transfer outb {:?}",ores.err().unwrap()}
164 }
165 outs = ores.unwrap().to_string();
166 }
167 if errb.len() > 0 {
168 let ores = std::str::from_utf8(&errb);
169 if ores.is_err() {
170 cmdpack_new_error!{CmdPackError,"can not transfer errb {:?}",ores.err().unwrap()}
171 }
172 errs = ores.unwrap().to_string();
173 }
174 Ok((outs,errs,exitcode))
175 }
176
177}
178
179
180#[derive(Clone)]
181pub struct CmdExec {
182 inner :Arc<RefCell<CmdExecInner>>,
183}
184
185impl Drop for CmdExec {
186 fn drop(&mut self) {
187 self.close();
188 }
189}
190
191impl CmdExec {
192 pub fn close(&mut self) {
193 debug_trace!("CmdExec close");
194 }
195 pub fn new(cmds :&[String]) -> Result<Self,Box<dyn Error>> {
196 let retv :Self = Self {
197 inner : Arc::new(RefCell::new(CmdExecInner::new(cmds)?)),
198 };
199 Ok(retv)
200 }
201
202 pub fn new_str(cmds :&[&str]) -> Result<Self,Box<dyn Error>> {
203 let retv :Self = Self {
204 inner : Arc::new(RefCell::new(CmdExecInner::new_str(cmds)?)),
205 };
206 Ok(retv)
207 }
208
209 pub fn run_bytes(&mut self,inputs :&[u8]) -> Result<(Vec<u8>,Vec<u8>,i32),Box<dyn Error>> {
210 return self.inner.borrow_mut().run_bytes(inputs);
211 }
212 pub fn run(&mut self,inputs :&str) -> Result<(String,String,i32),Box<dyn Error>> {
213 return self.inner.borrow_mut().run(inputs);
214 }
215}