}
}
+fn try_run(build: &Build, cmd: &mut Command) {
+ if build.flags.cmd.no_fail_fast() {
+ if !build.try_run(cmd) {
+ let failures = build.delayed_failures.get();
+ build.delayed_failures.set(failures + 1);
+ }
+ } else {
+ build.run(cmd);
+ }
+}
+
+#[allow(unused)]
+fn try_run_quiet(build: &Build, cmd: &mut Command) {
+ if build.flags.cmd.no_fail_fast() {
+ if !build.try_run_quiet(cmd) {
+ let failures = build.delayed_failures.get();
+ build.delayed_failures.set(failures + 1);
+ }
+ } else {
+ build.run_quiet(cmd);
+ }
+}
+
/// Runs the `linkchecker` tool as compiled in `stage` by the `host` compiler.
///
/// This tool in `src/tools` will verify the validity of all our links in the
let compiler = Compiler::new(0, host);
let _time = util::timeit();
- build.run(build.tool_cmd(&compiler, "linkchecker")
- .arg(build.out.join(host).join("doc")));
+ try_run(build, build.tool_cmd(&compiler, "linkchecker")
+ .arg(build.out.join(host).join("doc")));
}
/// Runs the `cargotest` tool as compiled in `stage` by the `host` compiler.
let _time = util::timeit();
let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest"));
build.prepare_tool_cmd(compiler, &mut cmd);
- build.run(cmd.env("PATH", newpath)
- .arg(&build.cargo)
- .arg(&out_dir));
+ try_run(build, cmd.env("PATH", newpath)
+ .arg(&build.cargo)
+ .arg(&out_dir));
}
/// Runs the `tidy` tool as compiled in `stage` by the `host` compiler.
if !build.config.vendor {
cmd.arg("--no-vendor");
}
- build.run(&mut cmd);
+ try_run(build, &mut cmd);
}
fn testdir(build: &Build, host: &str) -> PathBuf {
}
let _time = util::timeit();
- build.run(&mut cmd);
+ try_run(build, &mut cmd);
}
/// Run `rustdoc --test` for all documentation in `src/doc`.
}
cmd.arg("--test-args").arg(test_args);
- build.run(&mut cmd);
+ try_run(build, &mut cmd);
}
/// Run all unit tests plus documentation tests for an entire crate DAG defined
cargo.arg("--manifest-path")
.arg(build.src.join(path).join("Cargo.toml"))
.arg("--features").arg(features);
+ if test_kind.subcommand() == "test" && build.flags.cmd.no_fail_fast() {
+ cargo.arg("--no-fail-fast");
+ }
match krate {
Some(krate) => {
krate_qemu(build, &compiler, target, mode);
} else {
cargo.args(&build.flags.cmd.test_args());
- build.run(&mut cargo);
+ try_run(build, &mut cargo);
}
}
if build.config.quiet_tests {
cmd.arg("--quiet");
}
- build.run(&mut cmd);
+ try_run(build, &mut cmd);
}
}
cmd.arg("--quiet");
}
cmd.args(&build.flags.cmd.test_args());
- build.run(&mut cmd);
+ try_run(build, &mut cmd);
}
}
.current_dir(build.src.join("src/bootstrap"))
.env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
.env("RUSTC", &build.rustc);
+ if build.flags.cmd.no_fail_fast() {
+ cmd.arg("--no-fail-fast");
+ }
cmd.arg("--").args(&build.flags.cmd.test_args());
- build.run(&mut cmd);
+ try_run(build, &mut cmd);
}
Test {
paths: Vec<PathBuf>,
test_args: Vec<String>,
+ no_fail_fast: bool,
},
Bench {
paths: Vec<PathBuf>,
// Some subcommands get extra options
match subcommand.as_str() {
- "test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
+ "test" => {
+ opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
+ opts.optmulti("", "test-args", "extra arguments", "ARGS");
+ },
"bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
"dist" => { opts.optflag("", "install", "run installer as well"); },
_ => { },
Subcommand::Test {
paths: paths,
test_args: matches.opt_strs("test-args"),
+ no_fail_fast: matches.opt_present("no-fail-fast"),
}
}
"bench" => {
_ => Vec::new(),
}
}
+
+ pub fn no_fail_fast(&self) -> bool {
+ match *self {
+ Subcommand::Test { no_fail_fast, .. } => no_fail_fast,
+ _ => false,
+ }
+ }
}
fn split(s: Vec<String>) -> Vec<String> {
extern crate rustc_serialize;
extern crate toml;
+use std::cell::Cell;
use std::cmp;
use std::collections::HashMap;
use std::env;
use std::path::{Component, PathBuf, Path};
use std::process::Command;
-use build_helper::{run_silent, run_suppressed, output, mtime};
+use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime};
use util::{exe, libdir, add_lib_path};
crates: HashMap<String, Crate>,
is_sudo: bool,
src_is_git: bool,
+ delayed_failures: Cell<usize>,
}
#[derive(Debug)]
lldb_python_dir: None,
is_sudo: is_sudo,
src_is_git: src_is_git,
+ delayed_failures: Cell::new(0),
}
}
run_suppressed(cmd)
}
+ /// Runs a command, printing out nice contextual information if it fails.
+ /// Exits if the command failed to execute at all, otherwise returns its
+ /// `status.success()`.
+ fn try_run(&self, cmd: &mut Command) -> bool {
+ self.verbose(&format!("running: {:?}", cmd));
+ try_run_silent(cmd)
+ }
+
+ /// Runs a command, printing out nice contextual information if it fails.
+ /// Exits if the command failed to execute at all, otherwise returns its
+ /// `status.success()`.
+ #[allow(unused)]
+ fn try_run_quiet(&self, cmd: &mut Command) -> bool {
+ self.verbose(&format!("running: {:?}", cmd));
+ try_run_suppressed(cmd)
+ }
+
/// Prints a message if this build is configured in verbose mode.
fn verbose(&self, msg: &str) {
if self.flags.verbose() || self.config.verbose() {
use std::collections::{BTreeMap, HashSet, HashMap};
use std::mem;
+use std::process;
use check::{self, TestKind};
use compile;
let (kind, paths) = match self.build.flags.cmd {
Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
- Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]),
- Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]),
+ Subcommand::Test { ref paths, .. } => (Kind::Test, &paths[..]),
+ Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
Subcommand::Dist { ref paths, install } => {
if install {
return vec![self.sbuild.name("install")]
self.build.verbose(&format!("executing step {:?}", step));
(self.rules[step.name].run)(step);
}
+
+ // Check for postponed failures from `test --no-fail-fast`.
+ let failures = self.build.delayed_failures.get();
+ if failures > 0 {
+ println!("\n{} command(s) did not execute successfully.\n", failures);
+ process::exit(1);
+ }
}
/// From the top level targets `steps` generate a topological ordering of
}
pub fn run_silent(cmd: &mut Command) {
+ if !try_run_silent(cmd) {
+ std::process::exit(1);
+ }
+}
+
+pub fn try_run_silent(cmd: &mut Command) -> bool {
let status = match cmd.status() {
Ok(status) => status,
Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
cmd, e)),
};
if !status.success() {
- fail(&format!("command did not execute successfully: {:?}\n\
- expected success, got: {}",
- cmd,
- status));
+ println!("\n\ncommand did not execute successfully: {:?}\n\
+ expected success, got: {}\n\n",
+ cmd,
+ status);
}
+ status.success()
}
pub fn run_suppressed(cmd: &mut Command) {
+ if !try_run_suppressed(cmd) {
+ std::process::exit(1);
+ }
+}
+
+pub fn try_run_suppressed(cmd: &mut Command) -> bool {
let output = match cmd.output() {
Ok(status) => status,
Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}",
cmd, e)),
};
if !output.status.success() {
- fail(&format!("command did not execute successfully: {:?}\n\
- expected success, got: {}\n\n\
- stdout ----\n{}\n\
- stderr ----\n{}\n",
- cmd,
- output.status,
- String::from_utf8_lossy(&output.stdout),
- String::from_utf8_lossy(&output.stderr)));
+ println!("\n\ncommand did not execute successfully: {:?}\n\
+ expected success, got: {}\n\n\
+ stdout ----\n{}\n\
+ stderr ----\n{}\n\n",
+ cmd,
+ output.status,
+ String::from_utf8_lossy(&output.stdout),
+ String::from_utf8_lossy(&output.stderr));
}
+ output.status.success()
}
pub fn gnu_target(target: &str) -> String {