Refactor to use a dry-run config instead of cfg(test)

This ensures that each build will support the testing design of "dry
running" builds. It's also checked that a dry run build is equivalent
step-wise to a "wet" run build; the graphs we generate when running are
directly compared node/node and edge/edge, both for order and contents.
This commit is contained in:
Mark Simulacrum 2018-03-27 16:06:47 +02:00
parent b0dbc7c15d
commit a727447f59
12 changed files with 393 additions and 293 deletions

View file

@ -413,8 +413,9 @@ impl<'a> Builder<'a> {
builder
}
pub fn execute_cli(&self) {
pub fn execute_cli(&self) -> Graph<String, bool> {
self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths);
self.graph.borrow().clone()
}
pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
@ -910,6 +911,7 @@ impl<'a> Builder<'a> {
#[cfg(test)]
mod __test {
use config::Config;
use std::thread;
use super::*;
fn configure(host: &[&str], target: &[&str]) -> Config {
@ -917,6 +919,12 @@ mod __test {
// don't save toolstates
config.save_toolstates = None;
config.run_host_only = true;
config.dry_run = true;
// try to avoid spurious failures in dist where we create/delete each others file
let dir = config.out.join("tmp-rustbuild-tests")
.join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
t!(fs::create_dir_all(&dir));
config.out = dir;
config.build = INTERNER.intern_str("A");
config.hosts = vec![config.build].clone().into_iter()
.chain(host.iter().map(|s| INTERNER.intern_str(s))).collect::<Vec<_>>();

View file

@ -53,7 +53,7 @@ impl Step for Std {
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));
add_to_sysroot(&build, &libdir, &libstd_stamp(build, compiler, target));
}
}
@ -102,7 +102,7 @@ impl Step for Rustc {
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&libdir, &librustc_stamp(build, compiler, target));
add_to_sysroot(&build, &libdir, &librustc_stamp(build, compiler, target));
}
}
@ -143,7 +143,7 @@ impl Step for Test {
true);
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&libdir, &libtest_stamp(build, compiler, target));
add_to_sysroot(&build, &libdir, &libtest_stamp(build, compiler, target));
}
}

View file

@ -30,7 +30,7 @@ use build_helper::{output, mtime, up_to_date};
use filetime::FileTime;
use serde_json;
use util::{exe, libdir, is_dylib, copy, read_stamp_file, CiEnv};
use util::{exe, libdir, is_dylib, CiEnv};
use {Build, Compiler, Mode};
use native;
use tool;
@ -130,7 +130,7 @@ fn copy_musl_third_party_objects(build: &Build,
target: Interned<String>,
into: &Path) {
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
build.copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
}
}
@ -220,13 +220,13 @@ impl Step for StdLink {
target_compiler.host,
target);
let libdir = builder.sysroot_libdir(target_compiler, target);
add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));
add_to_sysroot(&build, &libdir, &libstd_stamp(build, compiler, target));
if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
// The sanitizers are only built in stage1 or above, so the dylibs will
// be missing in stage0 and causes panic. See the `std()` function above
// for reason why the sanitizers are not built in stage0.
copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir);
copy_apple_sanitizer_dylibs(&build, &build.native_dir(target), "osx", &libdir);
}
builder.ensure(tool::CleanTools {
@ -237,7 +237,7 @@ impl Step for StdLink {
}
}
fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) {
fn copy_apple_sanitizer_dylibs(build: &Build, native_dir: &Path, platform: &str, into: &Path) {
for &sanitizer in &["asan", "tsan"] {
let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
let mut src_path = native_dir.join(sanitizer);
@ -245,7 +245,7 @@ fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) {
src_path.push("lib");
src_path.push("darwin");
src_path.push(&filename);
copy(&src_path, &into.join(filename));
build.copy(&src_path, &into.join(filename));
}
}
@ -301,7 +301,7 @@ impl Step for StartupObjects {
.arg(src_file));
}
copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
build.copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
}
for obj in ["crt2.o", "dllcrt2.o"].iter() {
@ -309,7 +309,7 @@ impl Step for StartupObjects {
build.cc(target),
target,
obj);
copy(&src, &sysroot_dir.join(obj));
build.copy(&src, &sysroot_dir.join(obj));
}
}
}
@ -420,7 +420,7 @@ impl Step for TestLink {
&compiler.host,
target_compiler.host,
target);
add_to_sysroot(&builder.sysroot_libdir(target_compiler, target),
add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target),
&libtest_stamp(build, compiler, target));
builder.ensure(tool::CleanTools {
compiler: target_compiler,
@ -575,7 +575,7 @@ impl Step for RustcLink {
&compiler.host,
target_compiler.host,
target);
add_to_sysroot(&builder.sysroot_libdir(target_compiler, target),
add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target),
&librustc_stamp(build, compiler, target));
builder.ensure(tool::CleanTools {
compiler: target_compiler,
@ -690,7 +690,7 @@ impl Step for CodegenBackend {
cargo.arg("--features").arg(features),
&tmp_stamp,
false);
if cfg!(test) {
if builder.config.dry_run {
return;
}
let mut files = files.into_iter()
@ -736,6 +736,10 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder,
let dst = builder.sysroot_codegen_backends(target_compiler);
t!(fs::create_dir_all(&dst));
if builder.config.dry_run {
return;
}
for backend in builder.config.rust_codegen_backends.iter() {
let stamp = codegen_backend_stamp(build, compiler, target, *backend);
let mut dylib = String::new();
@ -751,7 +755,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder,
backend,
&filename[dot..])
};
copy(&file, &dst.join(target_filename));
build.copy(&file, &dst.join(target_filename));
}
}
@ -767,7 +771,7 @@ fn copy_lld_to_sysroot(builder: &Builder,
t!(fs::create_dir_all(&dst));
let exe = exe("lld", &target);
copy(&lld_install_root.join("bin").join(&exe), &dst.join(&exe));
builder.copy(&lld_install_root.join("bin").join(&exe), &dst.join(&exe));
}
/// Cargo's output path for the standard library in a given stage, compiled
@ -936,10 +940,10 @@ impl Step for Assemble {
let sysroot_libdir = sysroot.join(libdir(&*host));
t!(fs::create_dir_all(&sysroot_libdir));
let src_libdir = builder.sysroot_libdir(build_compiler, host);
for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) {
for f in builder.read_dir(&src_libdir) {
let filename = f.file_name().into_string().unwrap();
if is_dylib(&filename) {
copy(&f.path(), &sysroot_libdir.join(&filename));
builder.copy(&f.path(), &sysroot_libdir.join(&filename));
}
}
@ -957,7 +961,7 @@ impl Step for Assemble {
t!(fs::create_dir_all(&bindir));
let compiler = builder.rustc(target_compiler);
let _ = fs::remove_file(&compiler);
copy(&rustc, &compiler);
builder.copy(&rustc, &compiler);
target_compiler
}
@ -967,10 +971,10 @@ impl Step for Assemble {
///
/// For a particular stage this will link the file listed in `stamp` into the
/// `sysroot_dst` provided.
pub fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
pub fn add_to_sysroot(build: &Build, sysroot_dst: &Path, stamp: &Path) {
t!(fs::create_dir_all(&sysroot_dst));
for path in read_stamp_file(stamp) {
copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
for path in build.read_stamp_file(stamp) {
build.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
}
}
@ -1000,6 +1004,10 @@ fn stderr_isatty() -> bool {
pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool)
-> Vec<PathBuf>
{
if build.config.dry_run {
return Vec::new();
}
// `target_root_dir` looks like $dir/$target/release
let target_root_dir = stamp.parent().unwrap();
// `target_deps_dir` looks like $dir/$target/release/deps
@ -1141,6 +1149,9 @@ pub fn stream_cargo(
cargo: &mut Command,
cb: &mut FnMut(CargoMessage),
) -> bool {
if build.config.dry_run {
return true;
}
// Instruct Cargo to give us json messages on stdout, critically leaving
// stderr as piped so we can get those pretty colors.
cargo.arg("--message-format").arg("json")

View file

@ -15,7 +15,7 @@
use std::collections::{HashMap, HashSet};
use std::env;
use std::fs::File;
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process;
@ -69,6 +69,7 @@ pub struct Config {
pub jobs: Option<u32>,
pub cmd: Subcommand,
pub incremental: bool,
pub dry_run: bool,
// llvm codegen options
pub llvm_enabled: bool,
@ -362,8 +363,15 @@ impl Config {
config.jobs = flags.jobs;
config.cmd = flags.cmd;
config.incremental = flags.incremental;
config.dry_run = flags.dry_run;
config.keep_stage = flags.keep_stage;
if config.dry_run {
let dir = config.out.join("tmp-dry-run");
t!(fs::create_dir_all(&dir));
config.out = dir;
}
// If --target was specified but --host wasn't specified, don't run any host-only tests.
config.run_host_only = !(flags.host.is_empty() && !flags.target.is_empty());

View file

@ -20,7 +20,7 @@
use std::env;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::io::{Read, Write};
use std::path::{PathBuf, Path};
use std::process::{Command, Stdio};
@ -28,7 +28,7 @@ use build_helper::output;
use {Build, Compiler, Mode};
use channel;
use util::{cp_r, libdir, is_dylib, cp_filtered, copy, replace_in_file, exe};
use util::{libdir, is_dylib, exe};
use builder::{Builder, RunConfig, ShouldRun, Step};
use compile;
use native;
@ -103,7 +103,7 @@ impl Step for Docs {
let dst = image.join("share/doc/rust/html");
t!(fs::create_dir_all(&dst));
let src = build.doc_out(host);
cp_r(&src, &dst);
build.cp_r(&src, &dst);
let mut cmd = rust_installer(builder);
cmd.arg("generate")
@ -118,7 +118,7 @@ impl Step for Docs {
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--bulk-dirs=share/doc/rust/html");
build.run(&mut cmd);
t!(fs::remove_dir_all(&image));
build.remove_dir(&image);
distdir(build).join(format!("{}-{}.tar.gz", name, host))
}
@ -166,7 +166,7 @@ impl Step for RustcDocs {
let dst = image.join("share/doc/rust/html");
t!(fs::create_dir_all(&dst));
let src = build.compiler_doc_out(host);
cp_r(&src, &dst);
build.cp_r(&src, &dst);
let mut cmd = rust_installer(builder);
cmd.arg("generate")
@ -181,7 +181,7 @@ impl Step for RustcDocs {
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--bulk-dirs=share/doc/rust/html");
build.run(&mut cmd);
t!(fs::remove_dir_all(&image));
build.remove_dir(&image);
distdir(build).join(format!("{}-{}.tar.gz", name, host))
}
@ -292,31 +292,25 @@ fn make_win_dist(
let rustc_dlls = find_files(&rustc_dlls, &bin_path);
let target_libs = find_files(&target_libs, &lib_path);
fn copy_to_folder(src: &Path, dest_folder: &Path) {
let file_name = src.file_name().unwrap();
let dest = dest_folder.join(file_name);
copy(src, &dest);
}
//Copy runtime dlls next to rustc.exe
// Copy runtime dlls next to rustc.exe
let dist_bin_dir = rust_root.join("bin/");
fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
for src in rustc_dlls {
copy_to_folder(&src, &dist_bin_dir);
build.copy_to_folder(&src, &dist_bin_dir);
}
//Copy platform tools to platform-specific bin directory
let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
for src in target_tools {
copy_to_folder(&src, &target_bin_dir);
build.copy_to_folder(&src, &target_bin_dir);
}
//Copy platform libs to platform-specific lib directory
let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
for src in target_libs {
copy_to_folder(&src, &target_lib_dir);
build.copy_to_folder(&src, &target_lib_dir);
}
}
@ -417,7 +411,7 @@ impl Step for Rustc {
// Prepare the overlay which is part of the tarball but won't actually be
// installed
let cp = |file: &str| {
install(&build.src.join(file), &overlay, 0o644);
build.install(&build.src.join(file), &overlay, 0o644);
};
cp("COPYRIGHT");
cp("LICENSE-APACHE");
@ -425,9 +419,9 @@ impl Step for Rustc {
cp("README.md");
// tiny morsel of metadata is used by rust-packaging
let version = build.rust_version();
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
build.create(&overlay.join("version"), &version);
if let Some(sha) = build.rust_sha() {
t!(t!(File::create(overlay.join("git-commit-hash"))).write_all(sha.as_bytes()));
build.create(&overlay.join("git-commit-hash"), &sha);
}
// On MinGW we've got a few runtime DLL dependencies that we need to
@ -445,7 +439,7 @@ impl Step for Rustc {
let dst = image.join("share/doc");
t!(fs::create_dir_all(&dst));
cp_r(&build.src.join("src/etc/third-party"), &dst);
build.cp_r(&build.src.join("src/etc/third-party"), &dst);
}
// Finally, wrap everything up in a nice tarball!
@ -462,8 +456,8 @@ impl Step for Rustc {
.arg("--component-name=rustc")
.arg("--legacy-manifest-dirs=rustlib,cargo");
build.run(&mut cmd);
t!(fs::remove_dir_all(&image));
t!(fs::remove_dir_all(&overlay));
build.remove_dir(&image);
build.remove_dir(&overlay);
return distdir(build).join(format!("{}-{}.tar.gz", name, host));
@ -475,17 +469,17 @@ impl Step for Rustc {
// Copy rustc/rustdoc binaries
t!(fs::create_dir_all(image.join("bin")));
cp_r(&src.join("bin"), &image.join("bin"));
build.cp_r(&src.join("bin"), &image.join("bin"));
install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755);
build.install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755);
// Copy runtime DLLs needed by the compiler
if libdir != "bin" {
for entry in t!(src.join(libdir).read_dir()).map(|e| t!(e)) {
for entry in build.read_dir(&src.join(libdir)) {
let name = entry.file_name();
if let Some(s) = name.to_str() {
if is_dylib(s) {
install(&entry.path(), &image.join(libdir), 0o644);
build.install(&entry.path(), &image.join(libdir), 0o644);
}
}
}
@ -496,7 +490,7 @@ impl Step for Rustc {
let backends_rel = backends_src.strip_prefix(&src).unwrap();
let backends_dst = image.join(&backends_rel);
t!(fs::create_dir_all(&backends_dst));
cp_r(&backends_src, &backends_dst);
build.cp_r(&backends_src, &backends_dst);
// Copy over lld if it's there
if builder.config.lld_enabled {
@ -511,7 +505,7 @@ impl Step for Rustc {
.join("bin")
.join(&exe);
t!(fs::create_dir_all(&dst.parent().unwrap()));
copy(&src, &dst);
build.copy(&src, &dst);
}
// Man pages
@ -521,13 +515,12 @@ impl Step for Rustc {
let month_year = t!(time::strftime("%B %Y", &time::now()));
// don't use our `bootstrap::util::{copy, cp_r}`, because those try
// to hardlink, and we don't want to edit the source templates
for entry_result in t!(fs::read_dir(man_src)) {
let file_entry = t!(entry_result);
for file_entry in build.read_dir(&man_src) {
let page_src = file_entry.path();
let page_dst = man_dst.join(file_entry.file_name());
t!(fs::copy(&page_src, &page_dst));
// template in month/year and version number
replace_in_file(&page_dst,
build.replace_in_file(&page_dst,
&[("<INSERT DATE HERE>", &month_year),
("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM)]);
}
@ -540,7 +533,7 @@ impl Step for Rustc {
// Misc license info
let cp = |file: &str| {
install(&build.src.join(file), &image.join("share/doc/rust"), 0o644);
build.install(&build.src.join(file), &image.join("share/doc/rust"), 0o644);
};
cp("COPYRIGHT");
cp("LICENSE-APACHE");
@ -578,11 +571,11 @@ impl Step for DebuggerScripts {
let dst = sysroot.join("lib/rustlib/etc");
t!(fs::create_dir_all(&dst));
let cp_debugger_script = |file: &str| {
install(&build.src.join("src/etc/").join(file), &dst, 0o644);
build.install(&build.src.join("src/etc/").join(file), &dst, 0o644);
};
if host.contains("windows-msvc") {
// windbg debugger scripts
install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
build.install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
0o755);
cp_debugger_script("natvis/intrinsic.natvis");
@ -592,14 +585,14 @@ impl Step for DebuggerScripts {
cp_debugger_script("debugger_pretty_printers_common.py");
// gdb debugger scripts
install(&build.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
build.install(&build.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
0o755);
cp_debugger_script("gdb_load_rust_pretty_printers.py");
cp_debugger_script("gdb_rust_pretty_printing.py");
// lldb debugger scripts
install(&build.src.join("src/etc/rust-lldb"), &sysroot.join("bin"),
build.install(&build.src.join("src/etc/rust-lldb"), &sysroot.join("bin"),
0o755);
cp_debugger_script("lldb_rust_formatters.py");
@ -659,7 +652,7 @@ impl Step for Std {
t!(fs::create_dir_all(&dst));
let mut src = builder.sysroot_libdir(compiler, target).to_path_buf();
src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
cp_filtered(&src, &dst, &|path| {
build.cp_filtered(&src, &dst, &|path| {
let name = path.file_name().and_then(|s| s.to_str());
name != Some(build.config.rust_codegen_backends_dir.as_str()) &&
name != Some("bin")
@ -678,7 +671,7 @@ impl Step for Std {
.arg(format!("--component-name=rust-std-{}", target))
.arg("--legacy-manifest-dirs=rustlib,cargo");
build.run(&mut cmd);
t!(fs::remove_dir_all(&image));
build.remove_dir(&image);
distdir(build).join(format!("{}-{}.tar.gz", name, target))
}
}
@ -738,7 +731,7 @@ impl Step for Analysis {
let dst = image.join("lib/rustlib").join(target).join("analysis");
t!(fs::create_dir_all(&dst));
println!("image_src: {:?}, dst: {:?}", image_src, dst);
cp_r(&image_src, &dst);
build.cp_r(&image_src, &dst);
let mut cmd = rust_installer(builder);
cmd.arg("generate")
@ -752,7 +745,7 @@ impl Step for Analysis {
.arg(format!("--component-name=rust-analysis-{}", target))
.arg("--legacy-manifest-dirs=rustlib,cargo");
build.run(&mut cmd);
t!(fs::remove_dir_all(&image));
build.remove_dir(&image);
distdir(build).join(format!("{}-{}.tar.gz", name, target))
}
}
@ -796,7 +789,7 @@ fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_di
for item in src_dirs {
let dst = &dst_dir.join(item);
t!(fs::create_dir_all(dst));
cp_filtered(&build.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
build.cp_filtered(&build.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
}
}
@ -870,7 +863,7 @@ impl Step for Src {
copy_src_dirs(build, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
for file in src_files.iter() {
copy(&build.src.join(file), &dst_src.join(file));
build.copy(&build.src.join(file), &dst_src.join(file));
}
// Create source tarball in rust-installer format
@ -887,7 +880,7 @@ impl Step for Src {
.arg("--legacy-manifest-dirs=rustlib,cargo");
build.run(&mut cmd);
t!(fs::remove_dir_all(&image));
build.remove_dir(&image);
distdir(build).join(&format!("{}.tar.gz", name))
}
}
@ -943,13 +936,13 @@ impl Step for PlainSourceTarball {
// Copy the files normally
for item in &src_files {
copy(&build.src.join(item), &plain_dst_src.join(item));
build.copy(&build.src.join(item), &plain_dst_src.join(item));
}
// Create the version file
write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes());
build.create(&plain_dst_src.join("version"), &build.rust_version());
if let Some(sha) = build.rust_sha() {
write_file(&plain_dst_src.join("git-commit-hash"), sha.as_bytes());
build.create(&plain_dst_src.join("git-commit-hash"), &sha);
}
// If we're building from git sources, we need to vendor a complete distribution.
@ -990,7 +983,7 @@ impl Step for PlainSourceTarball {
tarball.set_extension(""); // strip .gz
tarball.set_extension(""); // strip .tar
if let Some(dir) = tarball.parent() {
t!(fs::create_dir_all(dir));
build.create_dir(&dir);
}
println!("running installer");
let mut cmd = rust_installer(builder);
@ -1004,26 +997,6 @@ impl Step for PlainSourceTarball {
}
}
fn install(src: &Path, dstdir: &Path, perms: u32) {
let dst = dstdir.join(src.file_name().unwrap());
t!(fs::create_dir_all(dstdir));
drop(fs::remove_file(&dst));
{
let mut s = t!(fs::File::open(&src));
let mut d = t!(fs::File::create(&dst));
io::copy(&mut s, &mut d).expect("failed to copy");
}
chmod(&dst, perms);
}
#[cfg(unix)]
fn chmod(path: &Path, perms: u32) {
use std::os::unix::fs::*;
t!(fs::set_permissions(path, fs::Permissions::from_mode(perms)));
}
#[cfg(windows)]
fn chmod(_path: &Path, _perms: u32) {}
// We have to run a few shell scripts, which choke quite a bit on both `\`
// characters and on `C:\` paths, so normalize both of them away.
pub fn sanitize_sh(path: &Path) -> String {
@ -1043,11 +1016,6 @@ pub fn sanitize_sh(path: &Path) -> String {
}
}
fn write_file(path: &Path, data: &[u8]) {
let mut vf = t!(fs::File::create(path));
t!(vf.write_all(data));
}
#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Cargo {
pub stage: u32,
@ -1084,38 +1052,38 @@ impl Step for Cargo {
let tmp = tmpdir(build);
let image = tmp.join("cargo-image");
drop(fs::remove_dir_all(&image));
t!(fs::create_dir_all(&image));
build.create_dir(&image);
// Prepare the image directory
t!(fs::create_dir_all(image.join("share/zsh/site-functions")));
t!(fs::create_dir_all(image.join("etc/bash_completion.d")));
build.create_dir(&image.join("share/zsh/site-functions"));
build.create_dir(&image.join("etc/bash_completion.d"));
let cargo = builder.ensure(tool::Cargo {
compiler: builder.compiler(stage, build.build),
target
});
install(&cargo, &image.join("bin"), 0o755);
build.install(&cargo, &image.join("bin"), 0o755);
for man in t!(etc.join("man").read_dir()) {
let man = t!(man);
install(&man.path(), &image.join("share/man/man1"), 0o644);
build.install(&man.path(), &image.join("share/man/man1"), 0o644);
}
install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
copy(&etc.join("cargo.bashcomp.sh"),
build.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
build.copy(&etc.join("cargo.bashcomp.sh"),
&image.join("etc/bash_completion.d/cargo"));
let doc = image.join("share/doc/cargo");
install(&src.join("README.md"), &doc, 0o644);
install(&src.join("LICENSE-MIT"), &doc, 0o644);
install(&src.join("LICENSE-APACHE"), &doc, 0o644);
install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
build.install(&src.join("README.md"), &doc, 0o644);
build.install(&src.join("LICENSE-MIT"), &doc, 0o644);
build.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
build.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
// Prepare the overlay
let overlay = tmp.join("cargo-overlay");
drop(fs::remove_dir_all(&overlay));
t!(fs::create_dir_all(&overlay));
install(&src.join("README.md"), &overlay, 0o644);
install(&src.join("LICENSE-MIT"), &overlay, 0o644);
install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
build.create_dir(&overlay);
build.install(&src.join("README.md"), &overlay, 0o644);
build.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
build.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
build.create(&overlay.join("version"), &version);
// Generate the installer tarball
let mut cmd = rust_installer(builder);
@ -1181,20 +1149,20 @@ impl Step for Rls {
target, extra_features: Vec::new()
}).or_else(|| { println!("Unable to build RLS, skipping dist"); None })?;
install(&rls, &image.join("bin"), 0o755);
build.install(&rls, &image.join("bin"), 0o755);
let doc = image.join("share/doc/rls");
install(&src.join("README.md"), &doc, 0o644);
install(&src.join("LICENSE-MIT"), &doc, 0o644);
install(&src.join("LICENSE-APACHE"), &doc, 0o644);
build.install(&src.join("README.md"), &doc, 0o644);
build.install(&src.join("LICENSE-MIT"), &doc, 0o644);
build.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
// Prepare the overlay
let overlay = tmp.join("rls-overlay");
drop(fs::remove_dir_all(&overlay));
t!(fs::create_dir_all(&overlay));
install(&src.join("README.md"), &overlay, 0o644);
install(&src.join("LICENSE-MIT"), &overlay, 0o644);
install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
build.install(&src.join("README.md"), &overlay, 0o644);
build.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
build.create(&overlay.join("version"), &version);
// Generate the installer tarball
let mut cmd = rust_installer(builder);
@ -1251,7 +1219,7 @@ impl Step for Rustfmt {
let tmp = tmpdir(build);
let image = tmp.join("rustfmt-image");
drop(fs::remove_dir_all(&image));
t!(fs::create_dir_all(&image));
build.create_dir(&image);
// Prepare the image directory
let rustfmt = builder.ensure(tool::Rustfmt {
@ -1263,21 +1231,21 @@ impl Step for Rustfmt {
target, extra_features: Vec::new()
}).or_else(|| { println!("Unable to build Cargofmt, skipping dist"); None })?;
install(&rustfmt, &image.join("bin"), 0o755);
install(&cargofmt, &image.join("bin"), 0o755);
build.install(&rustfmt, &image.join("bin"), 0o755);
build.install(&cargofmt, &image.join("bin"), 0o755);
let doc = image.join("share/doc/rustfmt");
install(&src.join("README.md"), &doc, 0o644);
install(&src.join("LICENSE-MIT"), &doc, 0o644);
install(&src.join("LICENSE-APACHE"), &doc, 0o644);
build.install(&src.join("README.md"), &doc, 0o644);
build.install(&src.join("LICENSE-MIT"), &doc, 0o644);
build.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
// Prepare the overlay
let overlay = tmp.join("rustfmt-overlay");
drop(fs::remove_dir_all(&overlay));
t!(fs::create_dir_all(&overlay));
install(&src.join("README.md"), &overlay, 0o644);
install(&src.join("LICENSE-MIT"), &overlay, 0o644);
install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
build.create_dir(&overlay);
build.install(&src.join("README.md"), &overlay, 0o644);
build.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
build.create(&overlay.join("version"), &version);
// Generate the installer tarball
let mut cmd = rust_installer(builder);
@ -1355,15 +1323,15 @@ impl Step for Extended {
let work = tmp.join("work");
let _ = fs::remove_dir_all(&overlay);
install(&build.src.join("COPYRIGHT"), &overlay, 0o644);
install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644);
install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
build.install(&build.src.join("COPYRIGHT"), &overlay, 0o644);
build.install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644);
build.install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
let version = build.rust_version();
t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes()));
build.create(&overlay.join("version"), &version);
if let Some(sha) = build.rust_sha() {
t!(t!(File::create(overlay.join("git-commit-hash"))).write_all(sha.as_bytes()));
build.create(&overlay.join("git-commit-hash"), &sha);
}
install(&etc.join("README.md"), &overlay, 0o644);
build.install(&etc.join("README.md"), &overlay, 0o644);
// When rust-std package split from rustc, we needed to ensure that during
// upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
@ -1402,11 +1370,11 @@ impl Step for Extended {
build.run(&mut cmd);
let mut license = String::new();
t!(t!(File::open(build.src.join("COPYRIGHT"))).read_to_string(&mut license));
license += &build.read(&build.src.join("COPYRIGHT"));
license += &build.read(&build.src.join("LICENSE-APACHE"));
license += &build.read(&build.src.join("LICENSE-MIT"));
license.push_str("\n");
t!(t!(File::open(build.src.join("LICENSE-APACHE"))).read_to_string(&mut license));
license.push_str("\n");
t!(t!(File::open(build.src.join("LICENSE-MIT"))).read_to_string(&mut license));
let rtf = r"{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Arial;}}\nowwrap\fs18";
let mut rtf = rtf.to_string();
@ -1463,10 +1431,10 @@ impl Step for Extended {
};
let prepare = |name: &str| {
t!(fs::create_dir_all(pkg.join(name)));
cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)),
build.create_dir(&pkg.join(name));
build.cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)),
&pkg.join(name));
install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
build.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
pkgbuild(name);
};
prepare("rustc");
@ -1480,12 +1448,12 @@ impl Step for Extended {
}
// create an 'uninstall' package
install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
build.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
pkgbuild("uninstall");
t!(fs::create_dir_all(pkg.join("res")));
t!(t!(File::create(pkg.join("res/LICENSE.txt"))).write_all(license.as_bytes()));
install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
build.create_dir(&pkg.join("res"));
build.create(&pkg.join("res/LICENSE.txt"), &license);
build.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
let mut cmd = Command::new("productbuild");
cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml")))
.arg("--resources").arg(pkg.join("res"))
@ -1501,7 +1469,7 @@ impl Step for Extended {
let _ = fs::remove_dir_all(&exe);
let prepare = |name: &str| {
t!(fs::create_dir_all(exe.join(name)));
build.create_dir(&exe.join(name));
let dir = if name == "rust-std" || name == "rust-analysis" {
format!("{}-{}", name, target)
} else if name == "rls" {
@ -1509,7 +1477,7 @@ impl Step for Extended {
} else {
name.to_string()
};
cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target))
build.cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target))
.join(dir),
&exe.join(name));
t!(fs::remove_file(exe.join(name).join("manifest.in")));
@ -1526,10 +1494,10 @@ impl Step for Extended {
prepare("rust-mingw");
}
install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
install(&etc.join("exe/modpath.iss"), &exe, 0o644);
install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
build.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
build.install(&etc.join("exe/modpath.iss"), &exe, 0o644);
build.install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
build.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
t!(t!(File::create(exe.join("LICENSE.txt"))).write_all(license.as_bytes()));
// Generate exe installer
@ -1541,7 +1509,7 @@ impl Step for Extended {
}
add_env(build, &mut cmd, target);
build.run(&mut cmd);
install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)),
build.install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)),
&distdir(build),
0o755);
@ -1666,8 +1634,8 @@ impl Step for Extended {
}
t!(t!(File::create(exe.join("LICENSE.rtf"))).write_all(rtf.as_bytes()));
install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
build.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
build.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
let filename = format!("{}-{}.msi", pkgname(build, "rust"), target);
let mut cmd = Command::new(&light);
@ -1772,7 +1740,7 @@ impl Step for HashSign {
cmd.arg(build.package_vers(&build.release_num("rustfmt")));
cmd.arg(addr);
t!(fs::create_dir_all(distdir(build)));
build.create_dir(&distdir(build));
let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));

View file

@ -26,11 +26,12 @@ use std::path::{PathBuf, Path};
use {Build, Mode};
use build_helper::up_to_date;
use util::{cp_r, symlink_dir};
use util::symlink_dir;
use builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
use tool::Tool;
use compile;
use cache::{INTERNER, Interned};
use config::Config;
macro_rules! book {
($($name:ident, $path:expr, $book_name:expr;)+) => {
@ -210,12 +211,13 @@ impl Step for RustbookSrc {
let src = src.join(name);
let index = out.join("index.html");
let rustbook = builder.tool_exe(Tool::Rustbook);
let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
return
}
println!("Rustbook ({}) - {}", target, name);
let _ = fs::remove_dir_all(&out);
build.run(builder.tool_cmd(Tool::Rustbook)
build.run(rustbook_cmd
.arg("build")
.arg(&src)
.arg("-d")
@ -370,7 +372,7 @@ impl Step for Standalone {
let version_input = build.src.join("src/doc/version_info.html.template");
let version_info = out.join("version_info.html");
if !up_to_date(&version_input, &version_info) {
if !build.config.dry_run && !up_to_date(&version_input, &version_info) {
let mut info = String::new();
t!(t!(File::open(&version_input)).read_to_string(&mut info));
let info = info.replace("VERSION", &build.rust_release())
@ -394,7 +396,7 @@ impl Step for Standalone {
up_to_date(&favicon, &html) &&
up_to_date(&full_toc, &html) &&
up_to_date(&version_info, &html) &&
up_to_date(&rustdoc, &html) {
(build.config.dry_run || up_to_date(&rustdoc, &html)) {
continue
}
@ -479,7 +481,7 @@ impl Step for Std {
// will also directly handle merging.
let my_out = build.crate_doc_out(target);
build.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&my_out, &out_dir));
t!(symlink_dir_force(&build.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc");
compile::std_cargo(builder, &compiler, target, &mut cargo);
@ -496,7 +498,7 @@ impl Step for Std {
}
build.run(&mut cargo);
cp_r(&my_out, &out);
build.cp_r(&my_out, &out);
}
}
@ -551,12 +553,12 @@ impl Step for Test {
// See docs in std above for why we symlink
let my_out = build.crate_doc_out(target);
build.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&my_out, &out_dir));
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc");
compile::test_cargo(build, &compiler, target, &mut cargo);
build.run(&mut cargo);
cp_r(&my_out, &out);
build.cp_r(&my_out, &out);
}
}
@ -617,7 +619,7 @@ impl Step for WhitelistedRustc {
// See docs in std above for why we symlink
let my_out = build.crate_doc_out(target);
build.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&my_out, &out_dir));
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
compile::rustc_cargo(build, &mut cargo);
@ -631,7 +633,7 @@ impl Step for WhitelistedRustc {
}
build.run(&mut cargo);
cp_r(&my_out, &out);
build.cp_r(&my_out, &out);
}
}
@ -693,7 +695,7 @@ impl Step for Rustc {
// We do not symlink to the same shared folder that already contains std library
// documentation from previous steps as we do not want to include that.
build.clear_if_dirty(&out, &rustdoc);
t!(symlink_dir_force(&out, &out_dir));
t!(symlink_dir_force(&builder.config, &out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
compile::rustc_cargo(build, &mut cargo);
@ -806,8 +808,8 @@ impl Step for UnstableBookGen {
println!("Generating unstable book md files ({})", target);
let out = build.md_doc_out(target).join("unstable-book");
t!(fs::create_dir_all(&out));
t!(fs::remove_dir_all(&out));
build.create_dir(&out);
build.remove_dir(&out);
let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
cmd.arg(build.src.join("src"));
cmd.arg(out);
@ -816,7 +818,10 @@ impl Step for UnstableBookGen {
}
}
fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> {
if config.dry_run {
return Ok(());
}
if let Ok(m) = fs::symlink_metadata(dst) {
if m.file_type().is_dir() {
try!(fs::remove_dir_all(dst));
@ -829,5 +834,5 @@ fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
}
}
symlink_dir(src, dst)
symlink_dir(config, src, dst)
}

View file

@ -13,7 +13,6 @@
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;
@ -42,6 +41,7 @@ pub struct Flags {
pub incremental: bool,
pub exclude: Vec<PathBuf>,
pub rustc_error_format: Option<String>,
pub dry_run: bool,
}
pub enum Subcommand {
@ -112,6 +112,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
opts.optmulti("", "target", "target targets to build", "TARGET");
opts.optmulti("", "exclude", "build paths to exclude", "PATH");
opts.optopt("", "on-fail", "command to run on failure", "CMD");
opts.optflag("", "dry-run", "dry run; don't build anything");
opts.optopt("", "stage", "stage to build", "N");
opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
@ -365,6 +366,7 @@ Arguments:
Flags {
verbose: matches.opt_count("verbose"),
stage,
dry_run: matches.opt_present("dry-run"),
on_fail: matches.opt_str("on-fail"),
rustc_error_format: matches.opt_str("error-format"),
keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),

View file

@ -114,7 +114,7 @@
//! also check out the `src/bootstrap/README.md` file for more information.
#![deny(warnings)]
#![feature(core_intrinsics)]
#![feature(conservative_impl_trait, fs_read_write, core_intrinsics)]
#![feature(slice_concat_ext)]
#[macro_use]
@ -143,13 +143,15 @@ extern crate libc;
use std::cell::{RefCell, Cell};
use std::collections::{HashSet, HashMap};
use std::env;
use std::fs::{self, File};
use std::io::Read;
use std::fs::{self, OpenOptions, File};
use std::io::{self, Seek, SeekFrom, Write, Read};
use std::path::{PathBuf, Path};
use std::process::{self, Command};
use std::slice;
use std::str;
use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime};
use filetime::FileTime;
use util::{exe, libdir, OutputFolder, CiEnv};
@ -404,13 +406,36 @@ impl Build {
return clean::clean(self, all);
}
let builder = builder::Builder::new(&self);
if let Some(path) = builder.paths.get(0) {
if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") {
return;
{
let builder = builder::Builder::new(&self);
if let Some(path) = builder.paths.get(0) {
if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") {
return;
}
}
}
builder.execute_cli();
if !self.config.dry_run {
let dry_graph = {
self.config.dry_run = true;
let builder = builder::Builder::new(&self);
builder.execute_cli()
};
self.config.dry_run = false;
let builder = builder::Builder::new(&self);
let act_graph = builder.execute_cli();
assert_eq!(dry_graph.raw_nodes().iter().map(|i| &i.weight).collect::<Vec<_>>(),
act_graph.raw_nodes().iter().map(|i| &i.weight).collect::<Vec<_>>());
assert_eq!(dry_graph.raw_edges()
.iter().map(|i| (&dry_graph[i.source()], &dry_graph[i.target()], &i.weight))
.collect::<Vec<_>>(),
act_graph.raw_edges()
.iter().map(|i| (&act_graph[i.source()], &act_graph[i.target()], &i.weight))
.collect::<Vec<_>>());
} else {
let builder = builder::Builder::new(&self);
let _ = builder.execute_cli();
}
// Check for postponed failures from `test --no-fail-fast`.
let failures = self.delayed_failures.borrow();
@ -997,8 +1022,168 @@ impl Build {
}
ret
}
fn read_stamp_file(&self, stamp: &Path) -> Vec<PathBuf> {
if self.config.dry_run {
return Vec::new();
}
let mut paths = Vec::new();
let mut contents = Vec::new();
t!(t!(File::open(stamp)).read_to_end(&mut contents));
// This is the method we use for extracting paths from the stamp file passed to us. See
// run_cargo for more information (in compile.rs).
for part in contents.split(|b| *b == 0) {
if part.is_empty() {
continue
}
let path = PathBuf::from(t!(str::from_utf8(part)));
paths.push(path);
}
paths
}
/// Copies a file from `src` to `dst`
pub fn copy(&self, src: &Path, dst: &Path) {
if self.config.dry_run { return; }
let _ = fs::remove_file(&dst);
// Attempt to "easy copy" by creating a hard link (symlinks don't work on
// windows), but if that fails just fall back to a slow `copy` operation.
if let Ok(()) = fs::hard_link(src, dst) {
return
}
if let Err(e) = fs::copy(src, dst) {
panic!("failed to copy `{}` to `{}`: {}", src.display(),
dst.display(), e)
}
let metadata = t!(src.metadata());
t!(fs::set_permissions(dst, metadata.permissions()));
let atime = FileTime::from_last_access_time(&metadata);
let mtime = FileTime::from_last_modification_time(&metadata);
t!(filetime::set_file_times(dst, atime, mtime));
}
/// Search-and-replaces within a file. (Not maximally efficiently: allocates a
/// new string for each replacement.)
pub fn replace_in_file(&self, path: &Path, replacements: &[(&str, &str)]) {
if self.config.dry_run { return; }
let mut contents = String::new();
let mut file = t!(OpenOptions::new().read(true).write(true).open(path));
t!(file.read_to_string(&mut contents));
for &(target, replacement) in replacements {
contents = contents.replace(target, replacement);
}
t!(file.seek(SeekFrom::Start(0)));
t!(file.set_len(0));
t!(file.write_all(contents.as_bytes()));
}
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
/// when this function is called.
pub fn cp_r(&self, src: &Path, dst: &Path) {
if self.config.dry_run { return; }
for f in t!(fs::read_dir(src)) {
let f = t!(f);
let path = f.path();
let name = path.file_name().unwrap();
let dst = dst.join(name);
if t!(f.file_type()).is_dir() {
t!(fs::create_dir_all(&dst));
self.cp_r(&path, &dst);
} else {
let _ = fs::remove_file(&dst);
self.copy(&path, &dst);
}
}
}
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
/// when this function is called. Unwanted files or directories can be skipped
/// by returning `false` from the filter function.
pub fn cp_filtered(&self, src: &Path, dst: &Path, filter: &Fn(&Path) -> bool) {
// Immediately recurse with an empty relative path
self.recurse_(src, dst, Path::new(""), filter)
}
// Inner function does the actual work
fn recurse_(&self, src: &Path, dst: &Path, relative: &Path, filter: &Fn(&Path) -> bool) {
for f in self.read_dir(src) {
let path = f.path();
let name = path.file_name().unwrap();
let dst = dst.join(name);
let relative = relative.join(name);
// Only copy file or directory if the filter function returns true
if filter(&relative) {
if t!(f.file_type()).is_dir() {
let _ = fs::remove_dir_all(&dst);
self.create_dir(&dst);
self.recurse_(&path, &dst, &relative, filter);
} else {
let _ = fs::remove_file(&dst);
self.copy(&path, &dst);
}
}
}
}
fn copy_to_folder(&self, src: &Path, dest_folder: &Path) {
let file_name = src.file_name().unwrap();
let dest = dest_folder.join(file_name);
self.copy(src, &dest);
}
fn install(&self, src: &Path, dstdir: &Path, perms: u32) {
if self.config.dry_run { return; }
let dst = dstdir.join(src.file_name().unwrap());
t!(fs::create_dir_all(dstdir));
drop(fs::remove_file(&dst));
{
let mut s = t!(fs::File::open(&src));
let mut d = t!(fs::File::create(&dst));
io::copy(&mut s, &mut d).expect("failed to copy");
}
chmod(&dst, perms);
}
fn create(&self, path: &Path, s: &str) {
if self.config.dry_run { return; }
t!(fs::write(path, s));
}
fn read(&self, path: &Path) -> String {
if self.config.dry_run { return String::new(); }
t!(fs::read_string(path))
}
fn create_dir(&self, dir: &Path) {
if self.config.dry_run { return; }
t!(fs::create_dir_all(dir))
}
fn remove_dir(&self, dir: &Path) {
if self.config.dry_run { return; }
t!(fs::remove_dir_all(dir))
}
fn read_dir(&self, dir: &Path) -> impl Iterator<Item=fs::DirEntry> {
let iter = match fs::read_dir(dir) {
Ok(v) => v,
Err(_) if self.config.dry_run => return vec![].into_iter(),
Err(err) => panic!("could not read dir {:?}: {:?}", dir, err),
};
iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
}
}
#[cfg(unix)]
fn chmod(path: &Path, perms: u32) {
use std::os::unix::fs::*;
t!(fs::set_permissions(path, fs::Permissions::from_mode(perms)));
}
#[cfg(windows)]
fn chmod(_path: &Path, _perms: u32) {}
impl<'a> Compiler {
pub fn with_stage(mut self, stage: u32) -> Compiler {
self.stage = stage;

View file

@ -60,9 +60,6 @@ impl Step for Llvm {
/// Compile LLVM for `target`.
fn run(self, builder: &Builder) -> PathBuf {
if cfg!(test) {
return PathBuf::from("llvm-config-test-generated");
}
let build = builder.build;
let target = self.target;
let emscripten = self.emscripten;
@ -220,6 +217,11 @@ impl Step for Llvm {
// libraries here, e.g. we just want a few components and a few
// tools. Figure out how to filter them down and only build the right
// tools and libs on all platforms.
if builder.config.dry_run {
return build_llvm_config;
}
cfg.build();
t!(t!(File::create(&done_stamp)).write_all(rebuild_trigger_contents.as_bytes()));
@ -339,7 +341,7 @@ impl Step for Lld {
/// Compile LLVM for `target`.
fn run(self, builder: &Builder) -> PathBuf {
if cfg!(test) {
if builder.config.dry_run {
return PathBuf::from("lld-out-dir-test-gen");
}
let target = self.target;
@ -395,7 +397,7 @@ impl Step for TestHelpers {
/// Compiles the `rust_test_helpers.c` library which we used in various
/// `run-pass` test suites for ABI testing.
fn run(self, builder: &Builder) {
if cfg!(test) {
if builder.config.dry_run {
return;
}
let build = builder.build;
@ -450,7 +452,7 @@ impl Step for Openssl {
}
fn run(self, builder: &Builder) {
if cfg!(test) {
if builder.config.dry_run {
return;
}
let build = builder.build;

View file

@ -1042,6 +1042,7 @@ impl Step for DocTest {
let _time = util::timeit();
let _folder = build.fold_output(|| format!("test_{}", self.name));
let mut files = Vec::new();
while let Some(p) = stack.pop() {
if p.is_dir() {
stack.extend(t!(p.read_dir()).map(|p| t!(p).path()));
@ -1058,7 +1059,13 @@ impl Step for DocTest {
continue;
}
let test_result = markdown_test(builder, compiler, &p);
files.push(p);
}
files.sort();
for file in files {
let test_result = markdown_test(builder, compiler, &file);
if self.is_ext_doc {
let toolstate = if test_result {
ToolState::TestPass

View file

@ -17,7 +17,7 @@ use std::slice::SliceConcatExt;
use Mode;
use Compiler;
use builder::{Step, RunConfig, ShouldRun, Builder};
use util::{copy, exe, add_lib_path};
use util::{exe, add_lib_path};
use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp};
use native;
use channel::GitInfo;
@ -207,7 +207,7 @@ impl Step for ToolBuild {
let cargo_out = build.cargo_out(compiler, Mode::Tool, target)
.join(exe(tool, &compiler.host));
let bin = build.tools_dir(compiler).join(exe(tool, &compiler.host));
copy(&cargo_out, &bin);
build.copy(&cargo_out, &bin);
Some(bin)
}
}
@ -443,7 +443,7 @@ impl Step for Rustdoc {
t!(fs::create_dir_all(&bindir));
let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host));
let _ = fs::remove_file(&bin_rustdoc);
copy(&tool_rustdoc, &bin_rustdoc);
build.copy(&tool_rustdoc, &bin_rustdoc);
bin_rustdoc
} else {
tool_rustdoc

View file

@ -15,13 +15,13 @@
use std::env;
use std::str;
use std::fs::{self, File, OpenOptions};
use std::io::{self, Read, Write, Seek, SeekFrom};
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::time::{SystemTime, Instant};
use filetime::{self, FileTime};
use config::Config;
/// Returns the `name` as the filename of a static library for `target`.
pub fn staticlib(name: &str, target: &str) -> String {
@ -32,102 +32,6 @@ pub fn staticlib(name: &str, target: &str) -> String {
}
}
/// Copies a file from `src` to `dst`
pub fn copy(src: &Path, dst: &Path) {
let _ = fs::remove_file(&dst);
// Attempt to "easy copy" by creating a hard link (symlinks don't work on
// windows), but if that fails just fall back to a slow `copy` operation.
if let Ok(()) = fs::hard_link(src, dst) {
return
}
if let Err(e) = fs::copy(src, dst) {
panic!("failed to copy `{}` to `{}`: {}", src.display(),
dst.display(), e)
}
let metadata = t!(src.metadata());
t!(fs::set_permissions(dst, metadata.permissions()));
let atime = FileTime::from_last_access_time(&metadata);
let mtime = FileTime::from_last_modification_time(&metadata);
t!(filetime::set_file_times(dst, atime, mtime));
}
/// Search-and-replaces within a file. (Not maximally efficiently: allocates a
/// new string for each replacement.)
pub fn replace_in_file(path: &Path, replacements: &[(&str, &str)]) {
let mut contents = String::new();
let mut file = t!(OpenOptions::new().read(true).write(true).open(path));
t!(file.read_to_string(&mut contents));
for &(target, replacement) in replacements {
contents = contents.replace(target, replacement);
}
t!(file.seek(SeekFrom::Start(0)));
t!(file.set_len(0));
t!(file.write_all(contents.as_bytes()));
}
pub fn read_stamp_file(stamp: &Path) -> Vec<PathBuf> {
let mut paths = Vec::new();
let mut contents = Vec::new();
t!(t!(File::open(stamp)).read_to_end(&mut contents));
// This is the method we use for extracting paths from the stamp file passed to us. See
// run_cargo for more information (in compile.rs).
for part in contents.split(|b| *b == 0) {
if part.is_empty() {
continue
}
let path = PathBuf::from(t!(str::from_utf8(part)));
paths.push(path);
}
paths
}
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
/// when this function is called.
pub fn cp_r(src: &Path, dst: &Path) {
for f in t!(fs::read_dir(src)) {
let f = t!(f);
let path = f.path();
let name = path.file_name().unwrap();
let dst = dst.join(name);
if t!(f.file_type()).is_dir() {
t!(fs::create_dir_all(&dst));
cp_r(&path, &dst);
} else {
let _ = fs::remove_file(&dst);
copy(&path, &dst);
}
}
}
/// Copies the `src` directory recursively to `dst`. Both are assumed to exist
/// when this function is called. Unwanted files or directories can be skipped
/// by returning `false` from the filter function.
pub fn cp_filtered(src: &Path, dst: &Path, filter: &Fn(&Path) -> bool) {
// Inner function does the actual work
fn recurse(src: &Path, dst: &Path, relative: &Path, filter: &Fn(&Path) -> bool) {
for f in t!(fs::read_dir(src)) {
let f = t!(f);
let path = f.path();
let name = path.file_name().unwrap();
let dst = dst.join(name);
let relative = relative.join(name);
// Only copy file or directory if the filter function returns true
if filter(&relative) {
if t!(f.file_type()).is_dir() {
let _ = fs::remove_dir_all(&dst);
t!(fs::create_dir(&dst));
recurse(&path, &dst, &relative, filter);
} else {
let _ = fs::remove_file(&dst);
copy(&path, &dst);
}
}
}
}
// Immediately recurse with an empty relative path
recurse(src, dst, Path::new(""), filter)
}
/// Given an executable called `name`, return the filename for the
/// executable for a particular target.
pub fn exe(name: &str, target: &str) -> String {
@ -214,8 +118,8 @@ impl Drop for TimeIt {
/// Symlinks two directories, using junctions on Windows and normal symlinks on
/// Unix.
pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
if cfg!(test) { return Ok(()); }
pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
if config.dry_run { return Ok(()); }
let _ = fs::remove_dir(dest);
return symlink_dir_inner(src, dest);