1use std::{
2 path::{Path, PathBuf},
3 fs::File,
4 fs,
5 io::prelude::*,
6 io::BufReader,
7 process::{Command, Stdio, Child}
8};
9
10pub fn shell(cwd: &Path, cmd: &str, args: &[&str]) -> Result<(), String> {
11 let mut cmd_build = Command::new(cmd);
12
13 cmd_build.args(args)
14 .current_dir(cwd);
15
16 let mut child = cmd_build.spawn().map_err( | e | format!("Error starting {} in dir {:?} - {:?}", cmd, cwd, e)) ?;
17
18 let r = child.wait().map_err( | e | format!("Process {} in dir {:?} returned error {:?} ", cmd, cwd, e)) ?;
19 if !r.success() {
20 return Err(format!("Process {} in dir {:?} returned error exit code {:?}", cmd, cwd, r.code()));
21 }
22 Ok(())
23}
24
25pub fn shell_env(env: &[(&str, &str)], cwd: &Path, cmd: &str, args: &[&str]) -> Result<(), String> {
26 let mut cmd_build = Command::new(cmd);
27
28 cmd_build.args(args)
29 .current_dir(cwd);
30
31 for (key, value) in env {
32 cmd_build.env(key, value);
33 }
34 let mut child = cmd_build.spawn().map_err( | e | format!("Error starting {} in dir {:?} - {:?}", cmd, cwd, e)) ?;
35
36 let r = child.wait().map_err( | e | format!("Process {} in dir {:?} returned error {:?} ", cmd, cwd, e)) ?;
37 if !r.success() {
38 return Err(format!("Process {} in dir {:?} returned error exit code {:?}", cmd, cwd, r.code()));
39 }
40 Ok(())
41}
42
43pub fn shell_env_cap(env: &[(&str, &str)], cwd: &Path, cmd: &str, args: &[&str]) -> Result<String, String> {
44 let mut cmd_build = Command::new(cmd);
45
46 cmd_build.args(args)
47 .stdout(Stdio::piped())
48 .stderr(Stdio::piped())
49 .current_dir(cwd);
50
51 for (key, value) in env {
52 cmd_build.env(key, value);
53 }
54 let child = cmd_build.spawn().map_err( | e | format!("Error starting {} in dir {:?} - {:?}", cmd, cwd, e)) ?;
55 let r = child.wait_with_output().map_err( | e | {
56 format!("Process {} in dir {:?} returned error {:?} ", cmd, cwd, e)
57 }) ?;
58 let stderr = std::str::from_utf8(&r.stderr).unwrap_or("could not decode utf8");
59 let stdout = std::str::from_utf8(&r.stdout).unwrap_or("could not decode utf8");
60 if !r.status.success() {
61 return Err(format!("Process {} in dir {:?} returned error exit code {}\n{}\n{}", cmd, cwd, r.status, stderr, stdout));
62 }
63 Ok(format!("{}{}", stdout, stderr))
64}
65
66pub struct ShellChild{
67 child: Child,
68 cwd: PathBuf,
69 cmd: String,
70}
71
72pub fn shell_child_create(env: &[(&str, &str)], cwd: &Path, cmd: &str, args: &[&str]) -> Result<ShellChild, String> {
73 let mut cmd_build = Command::new(cmd);
74
75 cmd_build.args(args)
76 .stdout(Stdio::piped())
77 .stderr(Stdio::piped())
78 .current_dir(cwd);
79
80 for (key, value) in env {
81 cmd_build.env(key, value);
82 }
83 let child = cmd_build.spawn().map_err( | e | format!("Error starting {} in dir {:?} - {:?}", cmd, cwd, e)) ?;
84 Ok(ShellChild{
85 child,
86 cwd: cwd.into(),
87 cmd: cmd.into()
88 })
89}
90
91
92pub fn shell_child_wait(child:ShellChild)-> Result<String, String> {
93 let r = child.child.wait_with_output().map_err( | e | {
94 format!("Process {} in dir {:?} returned error {:?} ", child.cmd, child.cwd, e)
95 }) ?;
96 let stderr = std::str::from_utf8(&r.stderr).unwrap_or("could not decode utf8");
97 let stdout = std::str::from_utf8(&r.stdout).unwrap_or("could not decode utf8");
98 if !r.status.success() {
99 return Err(format!("Process {} in dir {:?} returned error exit code {}\n{}\n{}", child.cmd, child.cwd, r.status, stderr, stdout));
100 }
101 Ok(format!("{}{}", stdout, stderr))
102}
103
104pub fn shell_env_cap_split(env: &[(&str, &str)], cwd: &Path, cmd: &str, args: &[&str]) -> (String, String, bool) {
105 let mut cmd_build = Command::new(cmd);
106
107 cmd_build.args(args)
108 .stdout(Stdio::piped())
109 .stderr(Stdio::piped())
110 .current_dir(cwd);
111
112 for (key, value) in env {
113 cmd_build.env(key, value);
114 }
115 let child = cmd_build.spawn();
116 if let Err(e) = child{
117 return ("".to_string(),format!("Cannot start process {}", e), false);
118 }
119 let r = child.unwrap().wait_with_output();
120 if let Err(e) = r{
121 return ("".to_string(),format!("Wait with output failed for process {}", e), false);
122 }
123 let r = r.unwrap();
124 let stderr = std::str::from_utf8(&r.stderr).unwrap_or("could not decode utf8").to_string();
125 let stdout = std::str::from_utf8(&r.stdout).unwrap_or("could not decode utf8").to_string();
126 (stdout, stderr, r.status.success())
127}
128
129pub fn shell_env_filter(start:&str, minus:Vec<String>, env: &[(&str, &str)], cwd: &Path, cmd: &str, args: &[&str]) -> Result<(), String> {
130
131 let mut cmd_build = Command::new(cmd);
132
133 cmd_build.args(args)
134 .stdin(Stdio::piped())
135 .stdout(Stdio::piped())
136 .current_dir(cwd);
137
138 for (key, value) in env {
139 cmd_build.env(key, value);
140 }
141
142 let mut child = cmd_build.spawn().map_err( | e | format!("Error starting {} in dir {:?} - {:?}", cmd, cwd, e)) ?;
143
144 let stdout = child.stdout.take().expect("stdout cannot be taken!");
145 let start = start.to_string();
146 let _stdout_thread = {
147 std::thread::spawn(move || {
148 let mut reader = BufReader::new(stdout);
149 let mut output = false;
150 'a: loop{
151 let mut line = String::new();
152 if let Ok(_) = reader.read_line(&mut line){
153 if line.contains(&start){
154 output = true;
155 }
156 if output{
157 for min in &minus{
158 if line.contains(min){
159 continue 'a;
160 }
161 }
162 println!("{}",line);
163 }
164 }
165 }
166 })
167 };
168
169 let r = child.wait().map_err( | e | format!("Process {} in dir {:?} returned error {:?} ", cmd, cwd, e)) ?;
170 if !r.success() {
171 return Err(format!("Process {} in dir {:?} returned error exit code {} ", cmd, cwd, r));
172 }
173 Ok(())
174}
175
176pub fn write_text(path: &Path, data:&str) -> Result<(), String> {
177 mkdir(path.parent().unwrap()) ?;
178 match fs::File::create(path) {
179 Err(e) => {
180 Err(format!("file create {:?} failed {:?}", path, e))
181 },
182 Ok(mut f) =>{
183 f.write_all(data.as_bytes())
184 .map_err( | _e | format!("Cant write file {:?}", path))
185 }
186 }
187}
188
189pub fn rmdir(path: &Path) -> Result<(), String> {
190 match fs::remove_dir_all(path) {
191 Err(e) => {
192 Err(format!("rmdir {:?} failed {:?}", path, e))
193 },
194 Ok(()) => Ok(())
195 }
196}
197
198
199pub fn mkdir(path: &Path) -> Result<(), String> {
200 match fs::create_dir_all(path) {
201 Err(e) => {
202 Err(format!("mkdir {:?} failed {:?}", path, e))
203 },
204 Ok(()) => Ok(())
205 }
206}
207
208pub fn rm(path: &Path) -> Result<(), String> {
209 match fs::remove_file(path) {
210 Err(e) => {
211 Err(format!("remove_file {:?} failed {:?}", path, e))
212 },
213 Ok(()) => Ok(())
214 }
215}
216
217
218#[allow(unused)]
219pub fn cp(source_path: &Path, dest_path: &Path, exec: bool) -> Result<(), String> {
220 let data = fs::read(source_path)
221 .map_err( | _e | format!("Cant open input file {:?}", source_path)) ?;
222 mkdir(dest_path.parent().unwrap()) ?;
223 let mut output = File::create(dest_path)
224 .map_err( | _e | format!("Cant open output file {:?}", dest_path)) ?;
225 output.write(&data)
226 .map_err( | _e | format!("Cant write output file {:?}", dest_path)) ?;
227 #[cfg(any(target_os = "macos", target_os = "linux"))]
228 if exec {
229 use std::os::unix::fs::PermissionsExt;
230 std::fs::set_permissions(dest_path, PermissionsExt::from_mode(0o744))
231 .map_err( | _e | format!("Cant set exec permissions on output file {:?}", dest_path)) ?;
232 }
233 Ok(())
234}
235
236pub fn cp_all(source_dir: &Path, dest_dir: &Path, exec: bool) -> Result<(), String> {
237 cp_all_recursive(source_dir, dest_dir, exec)?;
238 Ok(())
239}
240
241fn cp_all_recursive(source_dir: &Path, dest_dir: &Path, exec: bool) -> Result<(), String> {
242 if !source_dir.is_dir() {
243 return Err(format!("{:?} is not a directory", source_dir));
244 }
245
246 mkdir(dest_dir) ?;
247
248 for entry in fs::read_dir(source_dir).map_err(|_e| format!("Unable to read source directory {:?}", source_dir))? {
249 let entry = entry.map_err(|_e| format!("Unable to process directory entry"))?;
250 let source_path = entry.path();
251 if source_path.is_file() {
252 let dest_path = dest_dir.join(source_path.file_name()
253 .ok_or_else(|| format!("Unable to get filename for {:?}", source_path))?);
254
255 cp(&source_path, &dest_path, exec)?;
256 } else if source_path.is_dir() {
257 let dest_path = dest_dir.join(source_path.file_name()
258 .ok_or_else(|| format!("Unable to get folder name for {:?}", source_path))?);
259
260 cp_all_recursive(&source_path, &dest_path, exec)?;
261 }
262 }
263
264 Ok(())
265}
266
267
268pub fn walk_all(source_dir: &Path, dest_dir: &Path, cb:&mut dyn Fn(&Path, &Path)-> Result<(), String>) -> Result<(), String> {
269 walk_all_recursive(source_dir, dest_dir, cb)?;
270 Ok(())
271}
272
273fn walk_all_recursive(source_dir: &Path, dest_dir: &Path, cb:&mut dyn Fn(&Path, &Path)-> Result<(), String>) -> Result<(), String> {
274 if !source_dir.is_dir() {
275 return Err(format!("{:?} is not a directory", source_dir));
276 }
277
278 mkdir(dest_dir) ?;
279
280 for entry in fs::read_dir(source_dir).map_err(|_e| format!("Unable to read source directory {:?}", source_dir))? {
281 let entry = entry.map_err(|_e| format!("Unable to process directory entry"))?;
282 let source_path = entry.path();
283 if source_path.is_file() {
284 cb(&source_path, dest_dir)?;
285 } else if source_path.is_dir() {
296 let dest_path = dest_dir.join(source_path.file_name()
297 .ok_or_else(|| format!("Unable to get folder name for {:?}", source_path))?);
298
299 walk_all_recursive(&source_path, &dest_path, cb)?;
300 }
301 }
302
303 Ok(())
304}
305
306pub fn ls(dir: &Path) -> Result<Vec<PathBuf>, String> {
307 let mut result = Vec::new();
308 ls_recursive(dir, dir, &mut result)?;
309 Ok(result)
310}
311
312fn ls_recursive(dir: &Path, prefix: &Path, result: &mut Vec<PathBuf>) -> Result<(), String> {
313 for entry in fs::read_dir(dir).map_err(|_e| format!("Unable to read source directory {:?}", dir))? {
314 let entry = entry.map_err(|_e| format!("Unable to process directory entry"))?;
315 let source_path = entry.path();
316 if source_path.is_file() {
317 let file_name = source_path
318 .file_name()
319 .ok_or_else(|| format!("Unable to get filename"))?
320 .to_str()
321 .ok_or_else(|| format!( "Unable to convert filename to str"))?;
322
323 if !file_name.starts_with('.') {
324 let result_path = source_path.strip_prefix(prefix)
325 .map_err(|_e| format!("Unable to strip prefix"))?;
326 result.push(result_path.to_path_buf());
327 }
328 } else if source_path.is_dir() {
329 ls_recursive(&source_path, prefix, result)?;
330 }
331 }
332
333 Ok(())
334}