Skip to content

Commit 1ec160c

Browse files
committed
Implement blocking output
This allows decoupling `Command::spawn` and `Command::output`. This is useful for targets which do support launching programs in blocking mode but do not support multitasking (Eg: UEFI). This was originally conceived when working on rust-lang/rust#100316 Signed-off-by: Ayush Singh <[email protected]>
1 parent 025c3d4 commit 1ec160c

File tree

9 files changed

+61
-6
lines changed

9 files changed

+61
-6
lines changed

std/src/process.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -911,10 +911,8 @@ impl Command {
911911
/// ```
912912
#[stable(feature = "process", since = "1.0.0")]
913913
pub fn output(&mut self) -> io::Result<Output> {
914-
self.inner
915-
.spawn(imp::Stdio::MakePipe, false)
916-
.map(Child::from_inner)
917-
.and_then(|p| p.wait_with_output())
914+
let (status, stdout, stderr) = self.inner.output()?;
915+
Ok(Output { status: ExitStatus(status), stdout, stderr })
918916
}
919917

920918
/// Executes a command as a child process, waiting for it to finish and

std/src/sys/unix/process/process_fuchsia.rs

+5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ impl Command {
3535
Ok((Process { handle: Handle::new(process_handle) }, ours))
3636
}
3737

38+
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
39+
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
40+
crate::sys_common::process::wait_with_output(proc, pipes)
41+
}
42+
3843
pub fn exec(&mut self, default: Stdio) -> io::Error {
3944
if self.saw_nul() {
4045
return io::const_io_error!(

std/src/sys/unix/process/process_unix.rs

+5
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ impl Command {
132132
}
133133
}
134134

135+
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
136+
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
137+
crate::sys_common::process::wait_with_output(proc, pipes)
138+
}
139+
135140
// Attempts to fork the process. If successful, returns Ok((0, -1))
136141
// in the child, and Ok((child_pid, -1)) in the parent.
137142
#[cfg(not(target_os = "linux"))]

std/src/sys/unix/process/process_unsupported.rs

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ impl Command {
2020
unsupported()
2121
}
2222

23+
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
24+
unsupported()
25+
}
26+
2327
pub fn exec(&mut self, _default: Stdio) -> io::Error {
2428
unsupported_err()
2529
}

std/src/sys/unix/process/process_vxworks.rs

+5
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ impl Command {
108108
}
109109
}
110110

111+
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
112+
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
113+
crate::sys_common::process::wait_with_output(proc, pipes)
114+
}
115+
111116
pub fn exec(&mut self, default: Stdio) -> io::Error {
112117
let ret = Command::spawn(self, default, false);
113118
match ret {

std/src/sys/unsupported/pipe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ impl AnonPipe {
1515
self.0
1616
}
1717

18-
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
18+
pub fn read_to_end(&self, _buf: &mut Vec<u8>) -> io::Result<usize> {
1919
self.0
2020
}
2121

std/src/sys/unsupported/process.rs

+4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ impl Command {
7575
) -> io::Result<(Process, StdioPipes)> {
7676
unsupported()
7777
}
78+
79+
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
80+
unsupported()
81+
}
7882
}
7983

8084
impl From<AnonPipe> for Stdio {

std/src/sys/windows/process.rs

+5
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,11 @@ impl Command {
351351
))
352352
}
353353
}
354+
355+
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
356+
let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?;
357+
crate::sys_common::process::wait_with_output(proc, pipes)
358+
}
354359
}
355360

356361
impl fmt::Debug for Command {

std/src/sys_common/process.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
use crate::collections::BTreeMap;
55
use crate::env;
66
use crate::ffi::{OsStr, OsString};
7-
use crate::sys::process::EnvKey;
7+
use crate::io;
8+
use crate::sys::pipe::read2;
9+
use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};
810

911
// Stores a set of changes to an environment
1012
#[derive(Clone, Debug)]
@@ -117,3 +119,30 @@ impl<'a> ExactSizeIterator for CommandEnvs<'a> {
117119
self.iter.is_empty()
118120
}
119121
}
122+
123+
pub fn wait_with_output(
124+
mut process: Process,
125+
mut pipes: StdioPipes,
126+
) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
127+
drop(pipes.stdin.take());
128+
129+
let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
130+
match (pipes.stdout.take(), pipes.stderr.take()) {
131+
(None, None) => {}
132+
(Some(out), None) => {
133+
let res = out.read_to_end(&mut stdout);
134+
res.unwrap();
135+
}
136+
(None, Some(err)) => {
137+
let res = err.read_to_end(&mut stderr);
138+
res.unwrap();
139+
}
140+
(Some(out), Some(err)) => {
141+
let res = read2(out, &mut stdout, err, &mut stderr);
142+
res.unwrap();
143+
}
144+
}
145+
146+
let status = process.wait()?;
147+
Ok((status, stdout, stderr))
148+
}

0 commit comments

Comments
 (0)