1 // FIXME: This is a complete copy of `cargo/src/cargo/util/read2.rs`
2 // Consider unify the read2() in libstd, cargo and this to prevent further code duplication.
4 pub use self::imp::read2;
6 use std::process::{Child, Output};
8 pub fn read2_abbreviated(mut child: Child) -> io::Result<Output> {
10 use std::mem::replace;
12 const HEAD_LEN: usize = 160 * 1024;
13 const TAIL_LEN: usize = 256 * 1024;
17 Abbreviated { head: Vec<u8>, skipped: usize, tail: Box<[u8]> },
21 fn extend(&mut self, data: &[u8]) {
22 let new_self = match *self {
23 ProcOutput::Full(ref mut bytes) => {
24 bytes.extend_from_slice(data);
25 let new_len = bytes.len();
26 if new_len <= HEAD_LEN + TAIL_LEN {
29 let tail = bytes.split_off(new_len - TAIL_LEN).into_boxed_slice();
30 let head = replace(bytes, Vec::new());
31 let skipped = new_len - HEAD_LEN - TAIL_LEN;
32 ProcOutput::Abbreviated { head, skipped, tail }
34 ProcOutput::Abbreviated { ref mut skipped, ref mut tail, .. } => {
35 *skipped += data.len();
36 if data.len() <= TAIL_LEN {
37 tail[..data.len()].copy_from_slice(data);
38 tail.rotate_left(data.len());
40 tail.copy_from_slice(&data[(data.len() - TAIL_LEN)..]);
48 fn into_bytes(self) -> Vec<u8> {
50 ProcOutput::Full(bytes) => bytes,
51 ProcOutput::Abbreviated { mut head, skipped, tail } => {
52 write!(&mut head, "\n\n<<<<<< SKIPPED {} BYTES >>>>>>\n\n", skipped).unwrap();
53 head.extend_from_slice(&tail);
60 let mut stdout = ProcOutput::Full(Vec::new());
61 let mut stderr = ProcOutput::Full(Vec::new());
63 drop(child.stdin.take());
65 child.stdout.take().unwrap(),
66 child.stderr.take().unwrap(),
67 &mut |is_stdout, data, _| {
68 if is_stdout { &mut stdout } else { &mut stderr }.extend(data);
72 let status = child.wait()?;
74 Ok(Output { status, stdout: stdout.into_bytes(), stderr: stderr.into_bytes() })
77 #[cfg(not(any(unix, windows)))]
79 use std::io::{self, Read};
80 use std::process::{ChildStderr, ChildStdout};
83 out_pipe: ChildStdout,
84 err_pipe: ChildStderr,
85 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
87 let mut buffer = Vec::new();
88 out_pipe.read_to_end(&mut buffer)?;
89 data(true, &mut buffer, true);
91 err_pipe.read_to_end(&mut buffer)?;
92 data(false, &mut buffer, true);
100 use std::io::prelude::*;
102 use std::os::unix::prelude::*;
103 use std::process::{ChildStderr, ChildStdout};
106 mut out_pipe: ChildStdout,
107 mut err_pipe: ChildStderr,
108 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
109 ) -> io::Result<()> {
111 libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
112 libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
115 let mut out_done = false;
116 let mut err_done = false;
117 let mut out = Vec::new();
118 let mut err = Vec::new();
120 let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
121 fds[0].fd = out_pipe.as_raw_fd();
122 fds[0].events = libc::POLLIN;
123 fds[1].fd = err_pipe.as_raw_fd();
124 fds[1].events = libc::POLLIN;
129 // wait for either pipe to become readable using `select`
130 let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) };
132 let err = io::Error::last_os_error();
133 if err.kind() == io::ErrorKind::Interrupted {
139 // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
140 // EAGAIN. If we hit EOF, then this will happen because the underlying
141 // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
142 // this case we flip the other fd back into blocking mode and read
143 // whatever's leftover on that file descriptor.
144 let handle = |res: io::Result<_>| match res {
147 if e.kind() == io::ErrorKind::WouldBlock {
154 if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
158 data(false, &mut err, err_done);
159 if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
161 fds[0].fd = err_pipe.as_raw_fd();
165 data(true, &mut out, out_done);
174 use std::os::windows::prelude::*;
175 use std::process::{ChildStderr, ChildStdout};
178 use miow::iocp::{CompletionPort, CompletionStatus};
179 use miow::pipe::NamedPipe;
180 use miow::Overlapped;
181 use winapi::shared::winerror::ERROR_BROKEN_PIPE;
184 dst: &'a mut Vec<u8>,
185 overlapped: Overlapped,
191 out_pipe: ChildStdout,
192 err_pipe: ChildStderr,
193 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
194 ) -> io::Result<()> {
195 let mut out = Vec::new();
196 let mut err = Vec::new();
198 let port = CompletionPort::new(1)?;
199 port.add_handle(0, &out_pipe)?;
200 port.add_handle(1, &err_pipe)?;
203 let mut out_pipe = Pipe::new(out_pipe, &mut out);
204 let mut err_pipe = Pipe::new(err_pipe, &mut err);
209 let mut status = [CompletionStatus::zero(), CompletionStatus::zero()];
211 while !out_pipe.done || !err_pipe.done {
212 for status in port.get_many(&mut status, None)? {
213 if status.token() == 0 {
214 out_pipe.complete(status);
215 data(true, out_pipe.dst, out_pipe.done);
218 err_pipe.complete(status);
219 data(false, err_pipe.dst, err_pipe.done);
230 unsafe fn new<P: IntoRawHandle>(p: P, dst: &'a mut Vec<u8>) -> Pipe<'a> {
233 pipe: NamedPipe::from_raw_handle(p.into_raw_handle()),
234 overlapped: Overlapped::zero(),
239 unsafe fn read(&mut self) -> io::Result<()> {
240 let dst = slice_to_end(self.dst);
241 match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
244 if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
254 unsafe fn complete(&mut self, status: &CompletionStatus) {
255 let prev = self.dst.len();
256 self.dst.set_len(prev + status.bytes_transferred() as usize);
257 if status.bytes_transferred() == 0 {
263 unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
264 if v.capacity() == 0 {
267 if v.capacity() == v.len() {
270 slice::from_raw_parts_mut(v.as_mut_ptr().offset(v.len() as isize), v.capacity() - v.len())