Record build and test result of extended tools into toolstates.json.

This commit is contained in:
kennytm 2017-11-30 18:18:47 +08:00
parent 128199e39c
commit 971b1ba42b
No known key found for this signature in database
GPG key ID: FEF6C8051D0E013C
7 changed files with 68 additions and 12 deletions

View file

@ -301,6 +301,10 @@
# As a side-effect also generates MIR for all libraries. # As a side-effect also generates MIR for all libraries.
#test-miri = false #test-miri = false
# After building or testing extended tools (e.g. clippy and rustfmt), append the
# result (broken, compiling, testing) into this JSON file.
#save-toolstates = "/path/to/toolstates.json"
# ============================================================================= # =============================================================================
# Options for specific targets # Options for specific targets
# #

View file

@ -65,19 +65,21 @@ impl fmt::Display for TestKind {
} }
} }
fn try_run_expecting(build: &Build, cmd: &mut Command, expect: BuildExpectation) { fn try_run_expecting(build: &Build, cmd: &mut Command, expect: BuildExpectation) -> bool {
if !build.fail_fast { if !build.fail_fast {
if !build.try_run(cmd, expect) { if !build.try_run(cmd, expect) {
let mut failures = build.delayed_failures.borrow_mut(); let mut failures = build.delayed_failures.borrow_mut();
failures.push(format!("{:?}", cmd)); failures.push(format!("{:?}", cmd));
return false;
} }
} else { } else {
build.run_expecting(cmd, expect); build.run_expecting(cmd, expect);
} }
true
} }
fn try_run(build: &Build, cmd: &mut Command) { fn try_run(build: &Build, cmd: &mut Command) {
try_run_expecting(build, cmd, BuildExpectation::None) try_run_expecting(build, cmd, BuildExpectation::None);
} }
fn try_run_quiet(build: &Build, cmd: &mut Command) { fn try_run_quiet(build: &Build, cmd: &mut Command) {
@ -257,11 +259,13 @@ impl Step for Rls {
builder.add_rustc_lib_path(compiler, &mut cargo); builder.add_rustc_lib_path(compiler, &mut cargo);
try_run_expecting( if try_run_expecting(
build, build,
&mut cargo, &mut cargo,
builder.build.config.toolstate.rls.passes(ToolState::Testing), builder.build.config.toolstate.rls.passes(ToolState::Testing),
); ) {
build.save_toolstate("rls", ToolState::Testing);
}
} }
} }
@ -305,11 +309,13 @@ impl Step for Rustfmt {
builder.add_rustc_lib_path(compiler, &mut cargo); builder.add_rustc_lib_path(compiler, &mut cargo);
try_run_expecting( if try_run_expecting(
build, build,
&mut cargo, &mut cargo,
builder.build.config.toolstate.rustfmt.passes(ToolState::Testing), builder.build.config.toolstate.rustfmt.passes(ToolState::Testing),
); ) {
build.save_toolstate("rustfmt", ToolState::Testing);
}
} }
} }
@ -354,11 +360,13 @@ impl Step for Miri {
builder.add_rustc_lib_path(compiler, &mut cargo); builder.add_rustc_lib_path(compiler, &mut cargo);
try_run_expecting( if try_run_expecting(
build, build,
&mut cargo, &mut cargo,
builder.build.config.toolstate.miri.passes(ToolState::Testing), builder.build.config.toolstate.miri.passes(ToolState::Testing),
); ) {
build.save_toolstate("miri", ToolState::Testing);
}
} else { } else {
eprintln!("failed to test miri: could not build"); eprintln!("failed to test miri: could not build");
} }
@ -411,11 +419,13 @@ impl Step for Clippy {
builder.add_rustc_lib_path(compiler, &mut cargo); builder.add_rustc_lib_path(compiler, &mut cargo);
try_run_expecting( if try_run_expecting(
build, build,
&mut cargo, &mut cargo,
builder.build.config.toolstate.clippy.passes(ToolState::Testing), builder.build.config.toolstate.clippy.passes(ToolState::Testing),
); ) {
build.save_toolstate("clippy-driver", ToolState::Testing);
}
} else { } else {
eprintln!("failed to test clippy: could not build"); eprintln!("failed to test clippy: could not build");
} }

View file

@ -112,6 +112,8 @@ pub struct Config {
pub channel: String, pub channel: String,
pub quiet_tests: bool, pub quiet_tests: bool,
pub test_miri: bool, pub test_miri: bool,
pub save_toolstates: Option<PathBuf>,
// Fallback musl-root for all targets // Fallback musl-root for all targets
pub musl_root: Option<PathBuf>, pub musl_root: Option<PathBuf>,
pub prefix: Option<PathBuf>, pub prefix: Option<PathBuf>,
@ -279,6 +281,7 @@ struct Rust {
dist_src: Option<bool>, dist_src: Option<bool>,
quiet_tests: Option<bool>, quiet_tests: Option<bool>,
test_miri: Option<bool>, test_miri: Option<bool>,
save_toolstates: Option<String>,
} }
/// TOML representation of how each build target is configured. /// TOML representation of how each build target is configured.
@ -473,6 +476,7 @@ impl Config {
set(&mut config.test_miri, rust.test_miri); set(&mut config.test_miri, rust.test_miri);
config.rustc_default_linker = rust.default_linker.clone(); config.rustc_default_linker = rust.default_linker.clone();
config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.musl_root = rust.musl_root.clone().map(PathBuf::from);
config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from);
match rust.codegen_units { match rust.codegen_units {
Some(0) => config.rust_codegen_units = Some(num_cpus::get() as u32), Some(0) => config.rust_codegen_units = Some(num_cpus::get() as u32),

View file

@ -77,6 +77,7 @@ o("debuginfo", "rust.debuginfo", "build with debugger metadata")
o("debuginfo-lines", "rust.debuginfo-lines", "build with line number debugger metadata") o("debuginfo-lines", "rust.debuginfo-lines", "build with line number debugger metadata")
o("debuginfo-only-std", "rust.debuginfo-only-std", "build only libstd with debugging information") o("debuginfo-only-std", "rust.debuginfo-only-std", "build only libstd with debugging information")
o("debug-jemalloc", "rust.debug-jemalloc", "build jemalloc with --enable-debug --enable-fill") o("debug-jemalloc", "rust.debug-jemalloc", "build jemalloc with --enable-debug --enable-fill")
v("save-toolstates", "rust.save-toolstates", "save build and test status of external tools into this file")
v("prefix", "install.prefix", "set installation prefix") v("prefix", "install.prefix", "set installation prefix")
v("localstatedir", "install.localstatedir", "local state directory") v("localstatedir", "install.localstatedir", "local state directory")

View file

@ -190,6 +190,7 @@ mod job {
pub use config::Config; pub use config::Config;
use flags::Subcommand; use flags::Subcommand;
use cache::{Interned, INTERNER}; use cache::{Interned, INTERNER};
use toolstate::ToolState;
/// A structure representing a Rust compiler. /// A structure representing a Rust compiler.
/// ///
@ -874,6 +875,30 @@ impl Build {
} }
} }
/// Updates the actual toolstate of a tool.
///
/// The toolstates are saved to the file specified by the key
/// `rust.save-toolstates` in `config.toml`. If unspecified, nothing will be
/// done. The file is updated immediately after this function completes.
pub fn save_toolstate(&self, tool: &str, state: ToolState) {
use std::io::{Seek, SeekFrom};
if let Some(ref path) = self.config.save_toolstates {
let mut file = t!(fs::OpenOptions::new()
.create(true)
.read(true)
.write(true)
.open(path));
let mut current_toolstates: HashMap<Box<str>, ToolState> =
serde_json::from_reader(&mut file).unwrap_or_default();
current_toolstates.insert(tool.into(), state);
t!(file.seek(SeekFrom::Start(0)));
t!(file.set_len(0));
t!(serde_json::to_writer(file, &current_toolstates));
}
}
/// Get a list of crates from a root crate. /// Get a list of crates from a root crate.
/// ///
/// Returns Vec<(crate, path to crate, is_root_crate)> /// Returns Vec<(crate, path to crate, is_root_crate)>

View file

@ -115,7 +115,19 @@ impl Step for ToolBuild {
println!("Building stage{} tool {} ({})", compiler.stage, tool, target); println!("Building stage{} tool {} ({})", compiler.stage, tool, target);
let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path); let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path);
if !build.try_run(&mut cargo, expectation) { let is_expected = build.try_run(&mut cargo, expectation);
// If the expectation is "Failing", `try_run` returning true actually
// means a build-failure is successfully observed, i.e. the tool is
// broken. Thus the XOR here.
// Sorry for the complicated logic, but we can remove this expectation
// logic after #45861 is fully fixed.
build.save_toolstate(tool, if is_expected ^ (expectation == BuildExpectation::Failing) {
ToolState::Compiling
} else {
ToolState::Broken
});
if !is_expected {
if expectation == BuildExpectation::None { if expectation == BuildExpectation::None {
exit(1); exit(1);
} else { } else {

View file

@ -10,7 +10,7 @@
use build_helper::BuildExpectation; use build_helper::BuildExpectation;
#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
/// Whether a tool can be compiled, tested or neither /// Whether a tool can be compiled, tested or neither
pub enum ToolState { pub enum ToolState {
/// The tool compiles successfully, but the test suite fails /// The tool compiles successfully, but the test suite fails