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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
use std::{io, fs::File};
use io::{BufWriter, Write, BufReader, BufRead};
use std::process::{Command, Stdio, Output};
#[allow(clippy::manual_flatten)]
pub fn command_pipe_base<T> (
command: &mut Command, piped: &mut Command, piped_stdout: T
) -> Result<Output, io::Error> where T: Into<Stdio>{
let process = command.stdout(Stdio::piped()).spawn();
match process {
Ok(child) => {
if let Some(stdout) = child.stdout {
let piped_process = piped
.stdin(Stdio::piped())
.stdout(piped_stdout)
.spawn();
match piped_process {
Ok(mut piped_child) => {
if let Some(mut stdin) = piped_child.stdin.take() {
let mut writer = BufWriter::new(&mut stdin);
for line in BufReader::new(stdout).lines() {
if let Ok(l) = line {
writer.write_all(l.as_bytes()).unwrap();
writer.write_all(&[b'\n']).unwrap();
}
}
} else {
return Err(io::Error::new(
io::ErrorKind::BrokenPipe,
"Could not pipe command, stdin not found"
))
}
if let Ok(out) = piped_child.wait_with_output() {
return Ok(out)
} else {
return Err(io::Error::new(
io::ErrorKind::BrokenPipe,
"Could not wait for pipe"
))
}
},
Err(e) => return Err(e),
}
} else {
return Err(io::Error::new(
io::ErrorKind::BrokenPipe,
"Could not pipe command, stdout not found"
))
}
},
Err(e) => return Err(e),
}
}
pub fn command_pipe (
command: &mut Command, piped: &mut Command
) -> Result<Output, io::Error> {
return command_pipe_base(command, piped, Stdio::piped());
}
pub fn command_pipe_to_file (
command: &mut Command, piped: &mut Command, file: File
) -> Result<(), io::Error> {
return match command_pipe_base(command, piped, file) {
Ok(_) => Ok(()),
Err(e) => Err(e),
};
}
pub trait CmdPipe {
fn pipe (&mut self, piped_command: &mut Command) -> Result<Output, io::Error>;
fn pipe_to_file (&mut self, piped_command: &mut Command, file: File) -> Result<(), io::Error>;
}
impl CmdPipe for Command {
fn pipe(&mut self, piped_command: &mut Command) -> Result<Output, io::Error> {
command_pipe(self, piped_command)
}
fn pipe_to_file (&mut self, piped_command: &mut Command, file: File) -> Result<(), io::Error> {
command_pipe_to_file(self, piped_command, file)
}
}
#[cfg(test)]
mod test {
use std::fs;
use std::io::Read;
use std::process::Command;
use std::str::from_utf8;
use super::CmdPipe;
use super::command_pipe;
#[test]
fn test_command_to_pipe () {
let mut echo = Command::new("echo");
let mut wc = Command::new("wc");
let output = command_pipe(
&mut echo.args(["-n", "test"]),
&mut wc.arg("-c")
).unwrap();
let res = match from_utf8(&output.stdout) {
Ok(s) => s,
Err(_) => panic!("unexpected stdout"),
};
assert_eq!(str::trim_start(res), "5\n");
}
#[test]
fn test_command_pipe_trait () {
let mut echo = Command::new("echo");
let mut wc = Command::new("wc");
let output = echo.args(["-n", "test"])
.pipe(&mut wc.arg("-c"))
.unwrap();
let res = match from_utf8(&output.stdout) {
Ok(s) => s,
Err(_) => panic!("unexpected stdout"),
};
assert_eq!(str::trim_start(res), "5\n");
}
#[test]
fn test_command_pipe_to_file () {
const FILE_NAME: &str = "tmp/__command_pipe_to_file";
let mut echo = Command::new("echo");
let mut wc = Command::new("wc");
if let Err(e) = fs::create_dir("tmp") {
match e.kind() {
std::io::ErrorKind::AlreadyExists => (),
_ => panic!("{}", e),
}
}
let file = fs::File::create(FILE_NAME).unwrap();
echo.args(["-n", "test"])
.pipe_to_file(&mut wc.arg("-c"), file)
.unwrap();
let mut read_file = fs::File::open(FILE_NAME).unwrap();
let mut res = String::new();
match read_file.read_to_string(&mut res) {
Err(e) => panic!("{}", e),
_ => (),
};
assert_eq!(str::trim_start(&res), "5\n");
fs::remove_file(FILE_NAME).unwrap();
}
}