Skip to content

Commit

Permalink
Auto merge of #3091 - matklad:move-exec-streamed, r=alexcrichton
Browse files Browse the repository at this point in the history
Move stream_output to ProcessBuilder

Make `stream_output` method more reusable (I intend to use it in #3000).

Unrelated question: what is that `ExecEngine` thing? Looks like it does nothing at the moment and can be removed.
  • Loading branch information
bors authored Sep 26, 2016
2 parents 231dce6 + 5eb80b7 commit 4f57637
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 70 deletions.
63 changes: 5 additions & 58 deletions src/cargo/ops/cargo_rustc/custom_build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ use std::fs;
use std::path::{PathBuf, Path};
use std::str;
use std::sync::{Mutex, Arc};
use std::process::{Stdio, Output};

use core::PackageId;
use util::{CargoResult, Human};
use util::{CargoResult, Human, Freshness};
use util::{internal, ChainError, profile, paths};
use util::{Freshness, ProcessBuilder, read2};
use util::errors::{process_error, ProcessError};

use super::job::Work;
use super::job_queue::JobState;
use super::{fingerprint, Kind, Context, Unit};
use super::CommandType;

Expand Down Expand Up @@ -209,7 +205,10 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>)
// And now finally, run the build command itself!
state.running(&p);
let cmd = p.into_process_builder();
let output = try!(stream_output(state, &cmd).map_err(|mut e| {
let output = try!(cmd.exec_with_streaming(
&mut |out_line| state.stdout(out_line),
&mut |err_line| state.stderr(err_line),
).map_err(|mut e| {
e.desc = format!("failed to run custom build command for `{}`\n{}",
pkg_name, e.desc);
Human(e)
Expand Down Expand Up @@ -443,55 +442,3 @@ pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>,
}
}
}

fn stream_output(state: &JobState, cmd: &ProcessBuilder)
-> Result<Output, ProcessError> {
let mut stdout = Vec::new();
let mut stderr = Vec::new();

let status = try!((|| {
let mut cmd = cmd.build_command();
cmd.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null());
let mut child = try!(cmd.spawn());
let out = child.stdout.take().unwrap();
let err = child.stderr.take().unwrap();

try!(read2(out, err, &mut |is_out, data, eof| {
let idx = if eof {
data.len()
} else {
match data.iter().rposition(|b| *b == b'\n') {
Some(i) => i + 1,
None => return,
}
};
let data = data.drain(..idx);
let dst = if is_out {&mut stdout} else {&mut stderr};
let start = dst.len();
dst.extend(data);
let s = String::from_utf8_lossy(&dst[start..]);
if is_out {
state.stdout(&s);
} else {
state.stderr(&s);
}
}));
child.wait()
})().map_err(|e| {
let msg = format!("could not exeute process {}", cmd);
process_error(&msg, Some(e), None, None)
}));
let output = Output {
stdout: stdout,
stderr: stderr,
status: status,
};
if !output.status.success() {
let msg = format!("process didn't exit successfully: {}", cmd);
Err(process_error(&msg, None, Some(&status), Some(&output)))
} else {
Ok(output)
}
}
4 changes: 2 additions & 2 deletions src/cargo/ops/cargo_rustc/job_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,12 @@ impl<'a> JobQueue<'a> {
}
Message::Stdout(out) => {
if cx.config.extra_verbose() {
try!(write!(cx.config.shell().out(), "{}", out));
try!(writeln!(cx.config.shell().out(), "{}", out));
}
}
Message::Stderr(err) => {
if cx.config.extra_verbose() {
try!(write!(cx.config.shell().err(), "{}", err));
try!(writeln!(cx.config.shell().err(), "{}", err));
}
}
Message::Finish(result) => {
Expand Down
69 changes: 63 additions & 6 deletions src/cargo/util/process_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use std::env;
use std::ffi::{OsString, OsStr};
use std::fmt;
use std::path::Path;
use std::process::{Command, Output};
use std::process::{Command, Stdio, Output};

use util::{ProcessError, process_error};
use util::{ProcessError, process_error, read2};
use util::shell_escape::escape;

#[derive(Clone, PartialEq, Debug)]
Expand Down Expand Up @@ -75,15 +75,15 @@ impl ProcessBuilder {
pub fn exec(&self) -> Result<(), ProcessError> {
let mut command = self.build_command();
let exit = try!(command.status().map_err(|e| {
process_error(&format!("Could not execute process `{}`",
process_error(&format!("could not execute process `{}`",
self.debug_string()),
Some(e), None, None)
}));

if exit.success() {
Ok(())
} else {
Err(process_error(&format!("Process didn't exit successfully: `{}`",
Err(process_error(&format!("process didn't exit successfully: `{}`",
self.debug_string()),
None, Some(&exit), None))
}
Expand All @@ -93,20 +93,77 @@ impl ProcessBuilder {
let mut command = self.build_command();

let output = try!(command.output().map_err(|e| {
process_error(&format!("Could not execute process `{}`",
process_error(&format!("could not execute process `{}`",
self.debug_string()),
Some(e), None, None)
}));

if output.status.success() {
Ok(output)
} else {
Err(process_error(&format!("Process didn't exit successfully: `{}`",
Err(process_error(&format!("process didn't exit successfully: `{}`",
self.debug_string()),
None, Some(&output.status), Some(&output)))
}
}

pub fn exec_with_streaming(&self,
on_stdout_line: &mut FnMut(&str),
on_stderr_line: &mut FnMut(&str))
-> Result<Output, ProcessError> {
let mut stdout = Vec::new();
let mut stderr = Vec::new();

let mut cmd = self.build_command();
cmd.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::null());

let status = try!((|| {
let mut child = try!(cmd.spawn());
let out = child.stdout.take().unwrap();
let err = child.stderr.take().unwrap();
try!(read2(out, err, &mut |is_out, data, eof| {
let idx = if eof {
data.len()
} else {
match data.iter().rposition(|b| *b == b'\n') {
Some(i) => i + 1,
None => return,
}
};
let data = data.drain(..idx);
let dst = if is_out {&mut stdout} else {&mut stderr};
let start = dst.len();
dst.extend(data);
for line in String::from_utf8_lossy(&dst[start..]).lines() {
if is_out {
on_stdout_line(line)
} else {
on_stderr_line(line)
}
}
}));
child.wait()
})().map_err(|e| {
process_error(&format!("could not execute process `{}`",
self.debug_string()),
Some(e), None, None)
}));
let output = Output {
stdout: stdout,
stderr: stderr,
status: status,
};
if !output.status.success() {
Err(process_error(&format!("process didn't exit successfully: `{}`",
self.debug_string()),
None, Some(&output.status), Some(&output)))
} else {
Ok(output)
}
}

pub fn build_command(&self) -> Command {
let mut command = Command::new(&self.program);
if let Some(cwd) = self.get_cwd() {
Expand Down
2 changes: 1 addition & 1 deletion tests/build-script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ fn build_deps_not_for_normal() {
[ERROR] Could not compile `foo`.
Caused by:
Process didn't exit successfully: [..]
process didn't exit successfully: [..]
"));
}

Expand Down
2 changes: 1 addition & 1 deletion tests/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1967,7 +1967,7 @@ fn rustc_env_var() {
.env("RUSTC", "rustc-that-does-not-exist").arg("-v"),
execs().with_status(101)
.with_stderr("\
[ERROR] Could not execute process `rustc-that-does-not-exist -vV` ([..])
[ERROR] could not execute process `rustc-that-does-not-exist -vV` ([..])
Caused by:
[..]
Expand Down
4 changes: 2 additions & 2 deletions tests/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ fn exit_code() {
[COMPILING] foo v0.0.1 (file[..])
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `target[..]`
[ERROR] Process didn't exit successfully: `target[..]foo[..]` (exit code: 2)
[ERROR] process didn't exit successfully: `target[..]foo[..]` (exit code: 2)
"));
}

Expand All @@ -156,7 +156,7 @@ fn exit_code_verbose() {
[RUNNING] `rustc [..]`
[FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
[RUNNING] `target[..]`
[ERROR] Process didn't exit successfully: `target[..]foo[..]` (exit code: 2)
[ERROR] process didn't exit successfully: `target[..]foo[..]` (exit code: 2)
"));
}

Expand Down

0 comments on commit 4f57637

Please sign in to comment.