Skip to content

Commit eba942b

Browse files
authored
Add process-wrap integration (#13)
Adds support for the [`process-wrap`](https://docs.rs/process-wrap/latest/process_wrap/) crate.
1 parent c12cc59 commit eba942b

File tree

5 files changed

+306
-1
lines changed

5 files changed

+306
-1
lines changed

Cargo.lock

Lines changed: 188 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ push = false # Don't do `git push`.
2424
publish = false # Don't do `cargo publish`.
2525

2626
[dependencies]
27+
process-wrap = { version = "8", features = ["std"], optional = true }
2728
dyn-clone = "1.0.17"
2829
shell-words = "1"
2930
tracing = { version = "0", optional = true }
@@ -33,3 +34,6 @@ utf8-command = "1"
3334
indoc = "2.0.4"
3435
pretty_assertions = "1.4.0"
3536
static_assertions = "1.1.0"
37+
38+
[features]
39+
default = ["process-wrap"]

src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::CommandExt;
1919
#[derive(Debug)]
2020
#[non_exhaustive]
2121
pub enum Error {
22-
/// An execution failure, when a [`Command`] fails to start.
22+
/// An execution failure, when a [`Command`] fails to start or [`Child::wait`].
2323
Exec(ExecError),
2424
/// A failure to wait for a [`Command`].
2525
///

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,6 @@ pub use command_ext::CommandExt;
107107

108108
mod child_ext;
109109
pub use child_ext::ChildExt;
110+
111+
#[cfg(feature = "process-wrap")]
112+
mod process_wrap;

src/process_wrap.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use std::fmt::Debug;
2+
use std::fmt::Display;
3+
use std::process::Output;
4+
5+
use process_wrap::std::StdChildWrapper;
6+
use process_wrap::std::StdCommandWrap;
7+
8+
use crate::ChildContext;
9+
use crate::CommandExt;
10+
use crate::Error;
11+
use crate::ExecError;
12+
use crate::OutputContext;
13+
use crate::OutputConversionError;
14+
use crate::OutputLike;
15+
use crate::Utf8ProgramAndArgs;
16+
17+
impl 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+
}

0 commit comments

Comments
 (0)