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}