cmdpack/
lib.rs

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			//stdin.write_all(inputs.as_bytes());
136		}
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	    //debug_buffer_trace!(output.stdout.as_ptr(),output.stdout.len(),"{:?} output",self.cmds);
152	    //debug_buffer_trace!(output.stderr.as_ptr(),output.stderr.len(),"{:?} errout",self.cmds);
153	    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}