shellfn_core/execute/vec.rs
1use crate::error::Error;
2use crate::execute::execute_iter_nopanic_nopanic;
3use crate::utils::*;
4use std::error::Error as StdError;
5use std::ffi::OsStr;
6use std::io::{BufRead, BufReader};
7use std::str::FromStr;
8
9/// Executes command with args and environment variables, parses output line by line, returns after reading whole output
10/// * On invalid command: return error
11/// * On error exit code: return error
12/// * On parsing failure: collect error item
13/// * Possible errors: ProcessNotSpawned, WaitFailed, ProcessFailed, StdoutUnreadable (item error), ParsingError (item error)
14///
15/// Designed for
16/// ```rust
17/// use shellfn::shell;
18/// use std::error::Error;
19///
20/// #[shell]
21/// fn command() -> Result<Vec<Result<u32, Box<Error + 'static>>>, Box<Error>> {
22/// "echo 1; echo 2; echo 3"
23/// }
24///
25/// assert_eq!(vec![1, 2, 3], command().unwrap().map(Result::unwrap).collect::<Vec<_>>())
26/// ```
27pub fn execute_vec_result_result<T, TArg, TEnvKey, TEnvVal, TOuterError, TInnerError>(
28 cmd: impl AsRef<OsStr>,
29 args: impl IntoIterator<Item = TArg>,
30 envs: impl IntoIterator<Item = (TEnvKey, TEnvVal)>,
31) -> Result<Vec<Result<T, TInnerError>>, TOuterError>
32where
33 T: FromStr,
34 TArg: AsRef<OsStr>,
35 TEnvKey: AsRef<OsStr>,
36 TEnvVal: AsRef<OsStr>,
37 <T as FromStr>::Err: StdError,
38 TOuterError: From<Error<<T as FromStr>::Err>>,
39 TInnerError: From<Error<<T as FromStr>::Err>>,
40{
41 let mut process = spawn(cmd, args, envs).map_err(Error::ProcessNotSpawned)?;
42 let stdout = process.stdout.take().unwrap();
43 let result = BufReader::new(stdout)
44 .lines()
45 .map(|lres| {
46 lres.map_err(Error::StdoutUnreadable)
47 .map_err(Into::into)
48 .and_then(|line| {
49 line.parse()
50 .map_err(Error::ParsingError)
51 .map_err(Into::into)
52 })
53 })
54 .collect::<Vec<_>>();
55
56 check_exit_code(process)?;
57 Ok(result)
58}
59
60/// Executes command with args and environment variables, parses output line by line, returns after reading whole output
61/// * On invalid command: panic
62/// * On error exit code: panic
63/// * On parsing failure: panic
64/// * Possible errors: N/A
65///
66/// Designed for
67/// ```rust
68/// use shellfn::shell;
69/// use std::error::Error;
70///
71/// #[shell]
72/// fn command() -> Vec<u32> {
73/// "echo 1; echo 2; echo 3"
74/// }
75///
76/// assert_eq!(vec![1, 2, 3], command().collect::<Vec<_>>())
77/// ```
78pub fn execute_vec_panic_panic<T, TArg, TEnvKey, TEnvVal>(
79 cmd: impl AsRef<OsStr>,
80 args: impl IntoIterator<Item = TArg>,
81 envs: impl IntoIterator<Item = (TEnvKey, TEnvVal)>,
82) -> Vec<T>
83where
84 T: FromStr,
85 TArg: AsRef<OsStr>,
86 TEnvKey: AsRef<OsStr>,
87 TEnvVal: AsRef<OsStr>,
88 <T as FromStr>::Err: StdError,
89{
90 let mut process = spawn(cmd, args, envs).expect(PANIC_MSG);
91 let stdout = process.stdout.take().unwrap();
92 let result = BufReader::new(stdout)
93 .lines()
94 .map(|lres| lres.expect(PANIC_MSG).parse().expect(PANIC_MSG))
95 .collect::<Vec<_>>();
96
97 check_exit_code_panic(process);
98 result
99}
100
101/// Executes command with args and environment variables, parses output line by line, returns after reading whole output
102/// * On invalid command: panic
103/// * On error exit code: panic
104/// * On parsing failure: collect error item
105/// * Possible errors: StdoutUnreadable (item error), ParsingError (item error)
106///
107/// Designed for
108/// ```rust
109/// use shellfn::shell;
110/// use std::error::Error;
111///
112/// #[shell]
113/// fn command() -> Vec<Result<u32, Box<Error + 'static>>> {
114/// "echo 1; echo 2; echo 3"
115/// }
116///
117/// assert_eq!(vec![1, 2, 3], command().map(Result::unwrap).collect::<Vec<_>>())
118/// ```
119pub fn execute_vec_panic_result<T, TArg, TEnvKey, TEnvVal, TError>(
120 cmd: impl AsRef<OsStr>,
121 args: impl IntoIterator<Item = TArg>,
122 envs: impl IntoIterator<Item = (TEnvKey, TEnvVal)>,
123) -> Vec<Result<T, TError>>
124where
125 T: FromStr,
126 TArg: AsRef<OsStr>,
127 TEnvKey: AsRef<OsStr>,
128 TEnvVal: AsRef<OsStr>,
129 <T as FromStr>::Err: StdError,
130 TError: From<Error<<T as FromStr>::Err>>,
131{
132 let mut process = spawn(cmd, args, envs).expect(PANIC_MSG);
133 let stdout = process.stdout.take().unwrap();
134 let result = BufReader::new(stdout)
135 .lines()
136 .map(|lres| {
137 lres.map_err(Error::StdoutUnreadable)
138 .map_err(Into::into)
139 .and_then(|line| {
140 line.parse()
141 .map_err(Error::ParsingError)
142 .map_err(Into::into)
143 })
144 })
145 .collect::<Vec<_>>();
146
147 check_exit_code_panic(process);
148 result
149}
150
151/// Executes command with args and environment variables, parses output line by line, returns after reading whole output
152/// * On invalid command: return empty vec
153/// * On error exit code: return already collected items
154/// * On parsing failure: collect error item
155/// * Possible errors: StdoutUnreadable (item error), ParsingError (item error)
156///
157/// Designed for
158/// ```rust
159/// use shellfn::shell;
160/// use std::error::Error;
161///
162/// #[shell(no_panic)]
163/// fn command() -> Vec<Result<u32, Box<Error + 'static>>> {
164/// "echo 1; echo 2; echo 3"
165/// }
166///
167/// assert_eq!(vec![1, 2, 3], command().map(Result::unwrap).collect::<Vec<_>>())
168/// ```
169pub fn execute_vec_nopanic_result<T, TArg, TEnvKey, TEnvVal, TError>(
170 cmd: impl AsRef<OsStr>,
171 args: impl IntoIterator<Item = TArg>,
172 envs: impl IntoIterator<Item = (TEnvKey, TEnvVal)>,
173) -> Vec<Result<T, TError>>
174where
175 T: FromStr,
176 TArg: AsRef<OsStr>,
177 TEnvKey: AsRef<OsStr>,
178 TEnvVal: AsRef<OsStr>,
179 <T as FromStr>::Err: StdError,
180 TError: From<Error<<T as FromStr>::Err>>,
181{
182 spawn(cmd, args, envs)
183 .map(|mut process| {
184 BufReader::new(process.stdout.take().unwrap())
185 .lines()
186 .map(|lres| {
187 lres.map_err(Error::StdoutUnreadable)
188 .map_err(Into::into)
189 .and_then(|line| {
190 line.parse()
191 .map_err(Error::ParsingError)
192 .map_err(Into::into)
193 })
194 })
195 .collect::<Vec<_>>()
196 })
197 .unwrap_or(Vec::default())
198}
199
200/// Executes command with args and environment variables, parses output line by line, returns after reading whole output
201/// * On invalid command: return empty vec
202/// * On error exit code: return already collected items
203/// * On parsing failure: skip item
204/// * Possible errors: N/A
205///
206/// Designed for
207/// ```rust
208/// use shellfn::shell;
209/// use std::error::Error;
210///
211/// #[shell(no_panic)]
212/// fn command() -> Vec<u32> {
213/// "echo 1; echo 2; echo 3"
214/// }
215///
216/// assert_eq!(vec![1, 2, 3], command().collect::<Vec<_>>())
217/// ```
218pub fn execute_vec_nopanic_nopanic<T, TArg, TEnvKey, TEnvVal>(
219 cmd: impl AsRef<OsStr>,
220 args: impl IntoIterator<Item = TArg>,
221 envs: impl IntoIterator<Item = (TEnvKey, TEnvVal)>,
222) -> Vec<T>
223where
224 T: FromStr,
225 TArg: AsRef<OsStr>,
226 TEnvKey: AsRef<OsStr>,
227 TEnvVal: AsRef<OsStr>,
228 <T as FromStr>::Err: StdError,
229{
230 execute_iter_nopanic_nopanic(cmd, args, envs).collect()
231}
232
233/// Executes command with args and environment variables, parses output line by line, returns after reading whole output
234/// * On invalid command: return error
235/// * On error exit code: return error
236/// * On parsing failure: panic
237/// * Possible errors: ProcessNotSpawned, WaitFailed, ProcessFailed
238///
239/// Designed for
240/// ```rust
241/// use shellfn::shell;
242/// use std::error::Error;
243///
244/// #[shell]
245/// fn command() -> Result<Vec<u32>, Box<Error>> {
246/// "echo 1; echo 2; echo 3"
247/// }
248///
249/// assert_eq!(vec![1, 2, 3], command().unwrap().collect::<Vec<_>>())
250/// ```
251pub fn execute_vec_result_panic<T, TArg, TEnvKey, TEnvVal, TError>(
252 cmd: impl AsRef<OsStr>,
253 args: impl IntoIterator<Item = TArg>,
254 envs: impl IntoIterator<Item = (TEnvKey, TEnvVal)>,
255) -> Result<Vec<T>, TError>
256where
257 T: FromStr,
258 TArg: AsRef<OsStr>,
259 TEnvKey: AsRef<OsStr>,
260 TEnvVal: AsRef<OsStr>,
261 <T as FromStr>::Err: StdError,
262 TError: From<Error<<T as FromStr>::Err>>,
263{
264 let mut process = spawn(cmd, args, envs).map_err(Error::ProcessNotSpawned)?;
265 let stdout = process.stdout.take().unwrap();
266 let mut result = Vec::new();
267
268 for lres in BufReader::new(stdout).lines() {
269 result.push(lres.expect(PANIC_MSG).parse().expect(PANIC_MSG));
270 }
271
272 check_exit_code(process)?;
273 Ok(result)
274}
275
276/// Executes command with args and environment variables, parses output line by line, returns after reading whole output
277/// * On invalid command: return error
278/// * On error exit code: return error
279/// * On parsing failure: skip item
280/// * Possible errors: ProcessNotSpawned, WaitFailed, ProcessFailed
281///
282/// Designed for
283/// ```rust
284/// use shellfn::shell;
285/// use std::error::Error;
286///
287/// #[shell(no_panic)]
288/// fn command() -> Result<Vec<u32>, Box<Error>> {
289/// "echo 1; echo 2; echo 3"
290/// }
291///
292/// assert_eq!(vec![1, 2, 3], command().unwrap().collect::<Vec<_>>())
293/// ```
294pub fn execute_vec_result_nopanic<T, TArg, TEnvKey, TEnvVal, TError>(
295 cmd: impl AsRef<OsStr>,
296 args: impl IntoIterator<Item = TArg>,
297 envs: impl IntoIterator<Item = (TEnvKey, TEnvVal)>,
298) -> Result<Vec<T>, TError>
299where
300 T: FromStr,
301 TArg: AsRef<OsStr>,
302 TEnvKey: AsRef<OsStr>,
303 TEnvVal: AsRef<OsStr>,
304 <T as FromStr>::Err: StdError,
305 TError: From<Error<<T as FromStr>::Err>>,
306{
307 let mut process = spawn(cmd, args, envs).map_err(Error::ProcessNotSpawned)?;
308 let stdout = process.stdout.take().unwrap();
309 let result = BufReader::new(stdout)
310 .lines()
311 .filter_map(|lres| lres.ok().and_then(|line| line.parse().ok()))
312 .collect::<Vec<_>>();
313
314 check_exit_code(process)?;
315 Ok(result)
316}