1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
mod exit_status;
mod streams;
pub use self::{
exit_status::ExitStatus,
streams::{OutputStream, Stderr, Stdout},
};
use crate::{
FrameworkError,
FrameworkErrorKind::{ProcessError, TimeoutError},
};
use std::{
io::{self, Write},
process::{Child, ChildStdin},
sync::MutexGuard,
time::Duration,
};
use wait_timeout::ChildExt;
pub(super) type Guard<'cmd> = MutexGuard<'cmd, ()>;
#[derive(Debug)]
pub struct Process<'cmd> {
child: Child,
timeout: Duration,
stdout: Option<Stdout>,
stderr: Option<Stderr>,
stdin: ChildStdin,
guard: Option<Guard<'cmd>>,
}
impl<'cmd> Process<'cmd> {
pub(super) fn new(mut child: Child, timeout: Duration, guard: Option<Guard<'cmd>>) -> Self {
let stdout = child.stdout.take().map(Stdout::new);
let stderr = child.stderr.take().map(Stderr::new);
let stdin = child.stdin.take().unwrap();
Self {
child,
timeout,
stdout,
stderr,
stdin,
guard,
}
}
pub fn stdout(&mut self) -> &mut Stdout {
self.stdout
.as_mut()
.expect("child stdout not captured (use 'capture_stdout' method)")
}
pub fn stderr(&mut self) -> &mut Stderr {
self.stderr
.as_mut()
.expect("child stderr not captured (use 'capture_stderr' method)")
}
pub fn wait(mut self) -> Result<ExitStatus<'cmd>, FrameworkError> {
match self.child.wait_timeout(self.timeout)? {
Some(status) => {
let code = status.code().ok_or_else(|| {
format_err!(ProcessError, "no exit status returned from subprocess!")
})?;
Ok(ExitStatus::new(code, self.guard))
}
None => fail!(
TimeoutError,
"operation timed out after {} seconds",
self.timeout.as_secs()
),
}
}
}
impl<'cmd> Write for Process<'cmd> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.stdin.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.stdin.flush()
}
}