command_error/
process_wrap.rs

1use std::fmt::Debug;
2use std::fmt::Display;
3use std::process::Output;
4
5use process_wrap::std::StdChildWrapper;
6use process_wrap::std::StdCommandWrap;
7
8use crate::ChildContext;
9use crate::CommandExt;
10use crate::Error;
11use crate::ExecError;
12use crate::OutputContext;
13use crate::OutputConversionError;
14use crate::OutputLike;
15use crate::Utf8ProgramAndArgs;
16
17impl CommandExt for StdCommandWrap {
18    type Error = Error;
19    type Child = ChildContext<Box<dyn StdChildWrapper>>;
20
21    fn log(&self) -> Result<(), Self::Error> {
22        #[cfg(feature = "tracing")]
23        {
24            let command: Utf8ProgramAndArgs = self.command().into();
25            tracing::debug!(%command, "Executing command");
26        }
27        Ok(())
28    }
29
30    fn output_checked_as<O, R, E>(
31        &mut self,
32        succeeded: impl Fn(OutputContext<O>) -> Result<R, E>,
33    ) -> Result<R, E>
34    where
35        O: Debug + OutputLike + TryFrom<Output> + Send + Sync + 'static,
36        <O as TryFrom<Output>>::Error: Display + Send + Sync,
37        E: From<Self::Error> + Send + Sync,
38    {
39        self.log()?;
40        let displayed: Utf8ProgramAndArgs = self.command().into();
41        let child = match self.spawn() {
42            Ok(child) => child,
43            Err(inner) => {
44                return Err(Error::from(ExecError::new(Box::new(displayed), inner)).into());
45            }
46        };
47
48        match child.wait_with_output() {
49            Ok(output) => match output.try_into() {
50                Ok(output) => succeeded(OutputContext {
51                    output,
52                    command: Box::new(displayed),
53                }),
54                Err(error) => Err(Error::from(OutputConversionError {
55                    command: Box::new(displayed),
56                    inner: Box::new(error),
57                })
58                .into()),
59            },
60            Err(inner) => Err(Error::from(ExecError {
61                command: Box::new(displayed),
62                inner,
63            })
64            .into()),
65        }
66    }
67
68    fn status_checked_as<R, E>(
69        &mut self,
70        succeeded: impl Fn(OutputContext<std::process::ExitStatus>) -> Result<R, E>,
71    ) -> Result<R, E>
72    where
73        E: From<Self::Error>,
74    {
75        self.log()?;
76        let displayed: Utf8ProgramAndArgs = self.command().into();
77        let mut child = match self.spawn() {
78            Ok(child) => child,
79            Err(inner) => {
80                return Err(Error::from(ExecError::new(Box::new(displayed), inner)).into());
81            }
82        };
83
84        match child.wait() {
85            Ok(status) => succeeded(OutputContext {
86                output: status,
87                command: Box::new(displayed),
88            }),
89            Err(inner) => Err(Error::from(ExecError {
90                command: Box::new(displayed),
91                inner,
92            })
93            .into()),
94        }
95    }
96
97    fn spawn_checked(&mut self) -> Result<Self::Child, Self::Error> {
98        let displayed: Utf8ProgramAndArgs = self.command().into();
99        match self.spawn() {
100            Ok(child) => Ok(ChildContext {
101                child,
102                command: Box::new(displayed),
103            }),
104            Err(inner) => Err(Error::from(ExecError {
105                command: Box::new(displayed),
106                inner,
107            })),
108        }
109    }
110}