From 84b5b340216dc1f086d5de2c7d234aa5883cdce8 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 9 Mar 2018 18:14:35 -0700 Subject: [PATCH 01/13] Stop accessing current_dir in bootstrap This ensures that the working directory of rustbuild has no effect on it's run; since tests will run with a different cwd this is required for consistent behavior. --- src/bootstrap/bootstrap.py | 5 ++++- src/bootstrap/config.rs | 22 ++++++++++------------ src/bootstrap/flags.rs | 8 -------- src/bootstrap/lib.rs | 3 +-- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index eeac4436e6454..cf54591f25cd5 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -314,7 +314,7 @@ def __init__(self): self.build_dir = os.path.join(os.getcwd(), "build") self.clean = False self.config_toml = '' - self.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) + self.rust_root = '' self.use_locked_deps = '' self.use_vendored_sources = '' self.verbose = False @@ -710,6 +710,7 @@ def bootstrap(help_triggered): parser = argparse.ArgumentParser(description='Build rust') parser.add_argument('--config') parser.add_argument('--build') + parser.add_argument('--src') parser.add_argument('--clean', action='store_true') parser.add_argument('-v', '--verbose', action='count', default=0) @@ -718,6 +719,7 @@ def bootstrap(help_triggered): # Configure initial bootstrap build = RustBuild() + build.rust_root = args.src or os.path.abspath(os.path.join(__file__, '../../..')) build.verbose = args.verbose build.clean = args.clean @@ -788,6 +790,7 @@ def bootstrap(help_triggered): env["SRC"] = build.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) env["BOOTSTRAP_PYTHON"] = sys.executable + env["BUILD_DIR"] = build.build_dir run(args, env=env, verbose=build.verbose) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 33850debd3bdb..8df5f40661919 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -143,6 +143,7 @@ pub struct Config { // These are either the stage0 downloaded binaries or the locally installed ones. pub initial_cargo: PathBuf, pub initial_rustc: PathBuf, + pub out: PathBuf, } /// Per-target configuration stored in the global configuration structure. @@ -344,7 +345,8 @@ impl Config { config.rustc_error_format = flags.rustc_error_format; config.on_fail = flags.on_fail; config.stage = flags.stage; - config.src = flags.src; + // set by bootstrap.py + config.src = env::var_os("SRC").map(PathBuf::from).expect("'SRC' to be set"); config.jobs = flags.jobs; config.cmd = flags.cmd; config.incremental = flags.incremental; @@ -368,12 +370,8 @@ impl Config { }).unwrap_or_else(|| TomlConfig::default()); let build = toml.build.clone().unwrap_or(Build::default()); - set(&mut config.build, build.build.clone().map(|x| INTERNER.intern_string(x))); - set(&mut config.build, flags.build); - if config.build.is_empty() { - // set by bootstrap.py - config.build = INTERNER.intern_str(&env::var("BUILD").unwrap()); - } + // set by bootstrap.py + config.build = INTERNER.intern_str(&env::var("BUILD").unwrap()); config.hosts.push(config.build.clone()); for host in build.host.iter() { let host = INTERNER.intern_str(host); @@ -514,13 +512,13 @@ impl Config { let mut target = Target::default(); if let Some(ref s) = cfg.llvm_config { - target.llvm_config = Some(env::current_dir().unwrap().join(s)); + target.llvm_config = Some(config.src.join(s)); } if let Some(ref s) = cfg.jemalloc { - target.jemalloc = Some(env::current_dir().unwrap().join(s)); + target.jemalloc = Some(config.src.join(s)); } if let Some(ref s) = cfg.android_ndk { - target.ndk = Some(env::current_dir().unwrap().join(s)); + target.ndk = Some(config.src.join(s)); } target.cc = cfg.cc.clone().map(PathBuf::from); target.cxx = cfg.cxx.clone().map(PathBuf::from); @@ -541,8 +539,8 @@ impl Config { set(&mut config.rust_dist_src, t.src_tarball); } - let cwd = t!(env::current_dir()); - let out = cwd.join("build"); + let out = env::var_os("BUILD_DIR").map(PathBuf::from).expect("'BUILD_DIR' set"); + config.out = out.clone(); let stage0_root = out.join(&config.build).join("stage0/bin"); config.initial_rustc = match build.rustc { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index c5af0f8e2e153..60b22e35832f9 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -33,12 +33,10 @@ pub struct Flags { pub on_fail: Option, pub stage: Option, pub keep_stage: Option, - pub build: Option>, pub host: Vec>, pub target: Vec>, pub config: Option, - pub src: PathBuf, pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, @@ -278,10 +276,6 @@ Arguments: _ => { } }; // Get any optional paths which occur after the subcommand - let cwd = t!(env::current_dir()); - let src = matches.opt_str("src").map(PathBuf::from) - .or_else(|| env::var_os("SRC").map(PathBuf::from)) - .unwrap_or(cwd.clone()); let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { @@ -374,7 +368,6 @@ Arguments: 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()), - build: matches.opt_str("build").map(|s| INTERNER.intern_string(s)), host: split(matches.opt_strs("host")) .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), target: split(matches.opt_strs("target")) @@ -385,7 +378,6 @@ Arguments: incremental: matches.opt_present("incremental"), exclude: split(matches.opt_strs("exclude")) .into_iter().map(|p| p.into()).collect::>(), - src, } } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 833faf3618d67..8b19bff3f6af8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -309,9 +309,8 @@ impl Build { /// /// By default all build output will be placed in the current directory. pub fn new(config: Config) -> Build { - let cwd = t!(env::current_dir()); let src = config.src.clone(); - let out = cwd.join("build"); + let out = config.out.clone(); let is_sudo = match env::var_os("SUDO_USER") { Some(sudo_user) => { From a5e56b62c5bef0b171785d5b20b3fd4e714db528 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 9 Mar 2018 19:05:06 -0700 Subject: [PATCH 02/13] Permit constructing Builder without executing --- src/bootstrap/builder.rs | 19 ++++++++++--------- src/bootstrap/lib.rs | 8 +++++++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 0464840c3e818..6ae19ac394eec 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -42,6 +42,7 @@ pub struct Builder<'a> { cache: Cache, stack: RefCell>>, time_spent_on_dependencies: Cell, + pub paths: Vec, } impl<'a> Deref for Builder<'a> { @@ -351,6 +352,7 @@ impl<'a> Builder<'a> { cache: Cache::new(), stack: RefCell::new(Vec::new()), time_spent_on_dependencies: Cell::new(Duration::new(0, 0)), + paths: vec![], }; let builder = &builder; @@ -367,7 +369,7 @@ impl<'a> Builder<'a> { Some(help) } - pub fn run(build: &Build) { + pub fn new(build: &Build) -> Builder { let (kind, paths) = match build.config.cmd { Subcommand::Build { ref paths } => (Kind::Build, &paths[..]), Subcommand::Check { ref paths } => (Kind::Check, &paths[..]), @@ -379,12 +381,6 @@ impl<'a> Builder<'a> { Subcommand::Clean { .. } => panic!(), }; - if let Some(path) = paths.get(0) { - if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") { - return; - } - } - let builder = Builder { build, top_stage: build.config.stage.unwrap_or(2), @@ -392,15 +388,20 @@ impl<'a> Builder<'a> { cache: Cache::new(), stack: RefCell::new(Vec::new()), time_spent_on_dependencies: Cell::new(Duration::new(0, 0)), + paths: paths.to_owned(), }; if kind == Kind::Dist { - assert!(!build.config.test_miri, "Do not distribute with miri enabled.\n\ + assert!(!builder.config.test_miri, "Do not distribute with miri enabled.\n\ The distributed libraries would include all MIR (increasing binary size). The distributed MIR would include validation statements."); } - StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths); + builder + } + + pub fn execute_cli(&self) { + StepDescription::run(&Builder::get_step_descriptions(self.kind), self, &self.paths); } pub fn default_doc(&self, paths: Option<&[PathBuf]>) { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 8b19bff3f6af8..cbe19aeb63353 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -394,7 +394,13 @@ impl Build { self.verbose("learning about cargo"); metadata::build(self); - builder::Builder::run(&self); + 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(); // Check for postponed failures from `test --no-fail-fast`. let failures = self.delayed_failures.borrow(); From e7342b8f4233b67093c62c4044273185312aac59 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 9 Mar 2018 19:19:59 -0700 Subject: [PATCH 03/13] Permit constructing Build without executing --- src/bootstrap/lib.rs | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index cbe19aeb63353..cad4a794cf005 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -326,7 +326,7 @@ impl Build { let rls_info = channel::GitInfo::new(&config, &src.join("src/tools/rls")); let rustfmt_info = channel::GitInfo::new(&config, &src.join("src/tools/rustfmt")); - Build { + let mut build = Build { initial_rustc: config.initial_rustc.clone(), initial_cargo: config.initial_cargo.clone(), local_rebuild: config.local_rebuild, @@ -357,7 +357,27 @@ impl Build { delayed_failures: RefCell::new(Vec::new()), prerelease_version: Cell::new(None), tool_artifacts: Default::default(), + }; + + build.verbose("finding compilers"); + cc_detect::find(&mut build); + build.verbose("running sanity check"); + sanity::check(&mut build); + // If local-rust is the same major.minor as the current version, then force a local-rebuild + let local_version_verbose = output( + Command::new(&build.initial_rustc).arg("--version").arg("--verbose")); + let local_release = local_version_verbose + .lines().filter(|x| x.starts_with("release:")) + .next().unwrap().trim_left_matches("release:").trim(); + let my_version = channel::CFG_RELEASE_NUM; + if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { + build.verbose(&format!("auto-detected local-rebuild {}", local_release)); + build.local_rebuild = true; } + build.verbose("learning about cargo"); + metadata::build(&mut build); + + build } pub fn build_triple(&self) -> &[Interned] { @@ -376,24 +396,6 @@ impl Build { return clean::clean(self, all); } - self.verbose("finding compilers"); - cc_detect::find(self); - self.verbose("running sanity check"); - sanity::check(self); - // If local-rust is the same major.minor as the current version, then force a local-rebuild - let local_version_verbose = output( - Command::new(&self.initial_rustc).arg("--version").arg("--verbose")); - let local_release = local_version_verbose - .lines().filter(|x| x.starts_with("release:")) - .next().unwrap().trim_left_matches("release:").trim(); - let my_version = channel::CFG_RELEASE_NUM; - if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { - self.verbose(&format!("auto-detected local-rebuild {}", local_release)); - self.local_rebuild = true; - } - self.verbose("learning about cargo"); - metadata::build(self); - let builder = builder::Builder::new(&self); if let Some(path) = builder.paths.get(0) { if path == Path::new("nonexistent/path/to/trigger/cargo/metadata") { From cd33d3a0e49f67fdeebb8e19593f10b95e5719ee Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Fri, 9 Mar 2018 19:23:35 -0700 Subject: [PATCH 04/13] Stub out various functions during testing --- src/bootstrap/builder.rs | 2 +- src/bootstrap/compile.rs | 4 ++++ src/bootstrap/doc.rs | 1 + src/bootstrap/lib.rs | 29 +++++++++++++++++++---------- src/bootstrap/native.rs | 12 ++++++++++++ src/bootstrap/tool.rs | 6 +++++- src/bootstrap/util.rs | 3 +++ 7 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 6ae19ac394eec..c2a53e4590e78 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -687,7 +687,7 @@ impl<'a> Builder<'a> { // the options through environment variables that are fetched and understood by both. // // FIXME: the guard against msvc shouldn't need to be here - if !target.contains("msvc") { + if !target.contains("msvc") && !cfg!(test) { let ccache = self.config.ccache.as_ref(); let ccacheify = |s: &Path| { let ccache = match ccache { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e6aa78fba52ff..54b0ed6bb3595 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -690,6 +690,9 @@ impl Step for CodegenBackend { cargo.arg("--features").arg(features), &tmp_stamp, false); + if cfg!(test) { + return; + } let mut files = files.into_iter() .filter(|f| { let filename = f.file_name().unwrap().to_str().unwrap(); @@ -719,6 +722,7 @@ impl Step for CodegenBackend { fn copy_codegen_backends_to_sysroot(builder: &Builder, compiler: Compiler, target_compiler: Compiler) { + if cfg!(test) { return; } let build = builder.build; let target = target_compiler.host; diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 44073a5b07572..5f3d9ecfc042d 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -817,6 +817,7 @@ impl Step for UnstableBookGen { } fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> { + if cfg!(test) { return Ok(()); } if let Ok(m) = fs::symlink_metadata(dst) { if m.file_type().is_dir() { try!(fs::remove_dir_all(dst)); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index cad4a794cf005..a4287df677e3f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -363,16 +363,19 @@ impl Build { cc_detect::find(&mut build); build.verbose("running sanity check"); sanity::check(&mut build); - // If local-rust is the same major.minor as the current version, then force a local-rebuild - let local_version_verbose = output( - Command::new(&build.initial_rustc).arg("--version").arg("--verbose")); - let local_release = local_version_verbose - .lines().filter(|x| x.starts_with("release:")) - .next().unwrap().trim_left_matches("release:").trim(); - let my_version = channel::CFG_RELEASE_NUM; - if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { - build.verbose(&format!("auto-detected local-rebuild {}", local_release)); - build.local_rebuild = true; + if !cfg!(test) { + // If local-rust is the same major.minor as the current version, then force a + // local-rebuild + let local_version_verbose = output( + Command::new(&build.initial_rustc).arg("--version").arg("--verbose")); + let local_release = local_version_verbose + .lines().filter(|x| x.starts_with("release:")) + .next().unwrap().trim_left_matches("release:").trim(); + let my_version = channel::CFG_RELEASE_NUM; + if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { + build.verbose(&format!("auto-detected local-rebuild {}", local_release)); + build.local_rebuild = true; + } } build.verbose("learning about cargo"); metadata::build(&mut build); @@ -419,6 +422,7 @@ impl Build { /// /// After this executes, it will also ensure that `dir` exists. fn clear_if_dirty(&self, dir: &Path, input: &Path) -> bool { + if cfg!(test) { return true; } let stamp = dir.join(".stamp"); let mut cleared = false; if mtime(&stamp) < mtime(input) { @@ -593,12 +597,14 @@ impl Build { /// Runs a command, printing out nice contextual information if it fails. fn run(&self, cmd: &mut Command) { + if cfg!(test) { return; } self.verbose(&format!("running: {:?}", cmd)); run_silent(cmd) } /// Runs a command, printing out nice contextual information if it fails. fn run_quiet(&self, cmd: &mut Command) { + if cfg!(test) { return; } self.verbose(&format!("running: {:?}", cmd)); run_suppressed(cmd) } @@ -607,6 +613,7 @@ impl Build { /// Exits if the command failed to execute at all, otherwise returns its /// `status.success()`. fn try_run(&self, cmd: &mut Command) -> bool { + if cfg!(test) { return true; } self.verbose(&format!("running: {:?}", cmd)); try_run_silent(cmd) } @@ -615,6 +622,7 @@ impl Build { /// Exits if the command failed to execute at all, otherwise returns its /// `status.success()`. fn try_run_quiet(&self, cmd: &mut Command) -> bool { + if cfg!(test) { return true; } self.verbose(&format!("running: {:?}", cmd)); try_run_suppressed(cmd) } @@ -685,6 +693,7 @@ impl Build { /// Returns the path to the linker for the given target if it needs to be overridden. fn linker(&self, target: Interned) -> Option<&Path> { + if cfg!(test) { return None; } if let Some(linker) = self.config.target_config.get(&target) .and_then(|c| c.linker.as_ref()) { Some(linker) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index f923ad46bcbaa..f95f8e01dae50 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -60,6 +60,9 @@ 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; @@ -336,6 +339,9 @@ impl Step for Lld { /// Compile LLVM for `target`. fn run(self, builder: &Builder) -> PathBuf { + if cfg!(test) { + return PathBuf::from("lld-out-dir-test-gen"); + } let target = self.target; let build = builder.build; @@ -389,6 +395,9 @@ 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) { + return; + } let build = builder.build; let target = self.target; let dst = build.test_helpers_out(target); @@ -441,6 +450,9 @@ impl Step for Openssl { } fn run(self, builder: &Builder) { + if cfg!(test) { + return; + } let build = builder.build; let target = self.target; let out = match build.openssl_dir(target) { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 2bb46cc5171d6..362ec0c3b5085 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -199,7 +199,11 @@ impl Step for ToolBuild { if !is_expected { if !is_ext_tool { - exit(1); + if cfg!(test) { + panic!("unexpected failure -- would have hard exited"); + } else { + exit(1); + } } else { return None; } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 492eceef05c75..99d0548a05e7f 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -34,6 +34,7 @@ pub fn staticlib(name: &str, target: &str) -> String { /// Copies a file from `src` to `dst` pub fn copy(src: &Path, dst: &Path) { + if cfg!(test) { 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. @@ -66,6 +67,7 @@ pub fn replace_in_file(path: &Path, replacements: &[(&str, &str)]) { } pub fn read_stamp_file(stamp: &Path) -> Vec { + if cfg!(test) { return vec![]; } let mut paths = Vec::new(); let mut contents = Vec::new(); t!(t!(File::open(stamp)).read_to_end(&mut contents)); @@ -215,6 +217,7 @@ 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(()); } let _ = fs::remove_dir(dest); return symlink_dir_inner(src, dest); From fde70b09637c2ac50ac76c6916c42a2d1505117c Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 10 Mar 2018 07:01:06 -0700 Subject: [PATCH 05/13] Make test steps sortable Ensures that test cases will be somewhat easier to write. --- src/bootstrap/cache.rs | 14 ++++++++++++++ src/bootstrap/compile.rs | 12 ++++++------ src/bootstrap/dist.rs | 24 ++++++++++++------------ src/bootstrap/lib.rs | 2 +- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index c27493158826c..cbc77ab5bf42e 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -21,6 +21,7 @@ use std::mem; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::sync::Mutex; +use std::cmp::{PartialOrd, Ord, Ordering}; use builder::Step; @@ -154,6 +155,19 @@ impl AsRef for Interned { } } +impl PartialOrd> for Interned { + fn partial_cmp(&self, other: &Self) -> Option { + let l = INTERNER.strs.lock().unwrap(); + l.get(*self).partial_cmp(l.get(*other)) + } +} + +impl Ord for Interned { + fn cmp(&self, other: &Self) -> Ordering { + let l = INTERNER.strs.lock().unwrap(); + l.get(*self).cmp(l.get(*other)) + } +} struct TyIntern { items: Vec, diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 54b0ed6bb3595..d1a6a8d12a7c3 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -38,7 +38,7 @@ use tool; use cache::{INTERNER, Interned}; use builder::{Step, RunConfig, ShouldRun, Builder}; -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] pub struct Std { pub target: Interned, pub compiler: Compiler, @@ -314,10 +314,10 @@ impl Step for StartupObjects { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] pub struct Test { - pub compiler: Compiler, pub target: Interned, + pub compiler: Compiler, } impl Step for Test { @@ -430,10 +430,10 @@ impl Step for TestLink { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, PartialEq, Eq, Hash)] pub struct Rustc { - pub compiler: Compiler, pub target: Interned, + pub compiler: Compiler, } impl Step for Rustc { @@ -840,7 +840,7 @@ impl Step for Sysroot { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Copy, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)] pub struct Assemble { /// The compiler which we will produce in this step. Assemble itself will /// take care of ensuring that the necessary prerequisites to do so exist, diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 23b7b265a94be..cfa0cdecca6b3 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -61,7 +61,7 @@ fn rust_installer(builder: &Builder) -> Command { builder.tool_cmd(Tool::RustInstaller) } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Docs { pub stage: u32, pub host: Interned, @@ -320,9 +320,9 @@ fn make_win_dist( } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Mingw { - host: Interned, + pub host: Interned, } impl Step for Mingw { @@ -378,7 +378,7 @@ impl Step for Mingw { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustc { pub compiler: Compiler, } @@ -607,7 +607,7 @@ impl Step for DebuggerScripts { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Std { pub compiler: Compiler, pub target: Interned, @@ -800,7 +800,7 @@ fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_di } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Src; impl Step for Src { @@ -894,7 +894,7 @@ impl Step for Src { const CARGO_VENDOR_VERSION: &str = "0.1.4"; -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct PlainSourceTarball; impl Step for PlainSourceTarball { @@ -1048,7 +1048,7 @@ fn write_file(path: &Path, data: &[u8]) { t!(vf.write_all(data)); } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Cargo { pub stage: u32, pub target: Interned, @@ -1135,7 +1135,7 @@ impl Step for Cargo { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rls { pub stage: u32, pub target: Interned, @@ -1216,7 +1216,7 @@ impl Step for Rls { } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustfmt { pub stage: u32, pub target: Interned, @@ -1298,7 +1298,7 @@ impl Step for Rustfmt { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Extended { stage: u32, host: Interned, @@ -1731,7 +1731,7 @@ fn add_env(build: &Build, cmd: &mut Command, target: Interned) { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct HashSign; impl Step for HashSign { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a4287df677e3f..cb3a9dfbf3c11 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -198,7 +198,7 @@ use toolstate::ToolState; /// Each compiler has a `stage` that it is associated with and a `host` that /// corresponds to the platform the compiler runs on. This structure is used as /// a parameter to many methods below. -#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)] +#[derive(Eq, PartialOrd, Ord, PartialEq, Clone, Copy, Hash, Debug)] pub struct Compiler { stage: u32, host: Interned, From 8fd42ec130148cb49e83028153f17dab6843966e Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 10 Mar 2018 07:02:17 -0700 Subject: [PATCH 06/13] Extract default Config into function Will permit creating Config in tests without having to parse a toml file. --- src/bootstrap/config.rs | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 8df5f40661919..0848590a9bc10 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -318,11 +318,8 @@ struct TomlTarget { } impl Config { - pub fn parse(args: &[String]) -> Config { - let flags = Flags::parse(&args); - let file = flags.config.clone(); + pub fn default_opts() -> Config { let mut config = Config::default(); - config.exclude = flags.exclude; config.llvm_enabled = true; config.llvm_optimize = true; config.llvm_version_check = true; @@ -342,11 +339,26 @@ impl Config { config.rust_codegen_backends = vec![INTERNER.intern_str("llvm")]; config.rust_codegen_backends_dir = "codegen-backends".to_owned(); + // set by bootstrap.py + config.src = env::var_os("SRC").map(PathBuf::from).expect("'SRC' to be set"); + config.build = INTERNER.intern_str(&env::var("BUILD").expect("'BUILD' to be set")); + config.out = env::var_os("BUILD_DIR").map(PathBuf::from).expect("'BUILD_DIR' set"); + + let stage0_root = config.out.join(&config.build).join("stage0/bin"); + config.initial_rustc = stage0_root.join(exe("rustc", &config.build)); + config.initial_cargo = stage0_root.join(exe("cargo", &config.build)); + + config + } + + pub fn parse(args: &[String]) -> Config { + let flags = Flags::parse(&args); + let file = flags.config.clone(); + let mut config = Config::default_opts(); + config.exclude = flags.exclude; config.rustc_error_format = flags.rustc_error_format; config.on_fail = flags.on_fail; config.stage = flags.stage; - // set by bootstrap.py - config.src = env::var_os("SRC").map(PathBuf::from).expect("'SRC' to be set"); config.jobs = flags.jobs; config.cmd = flags.cmd; config.incremental = flags.incremental; @@ -371,7 +383,6 @@ impl Config { let build = toml.build.clone().unwrap_or(Build::default()); // set by bootstrap.py - config.build = INTERNER.intern_str(&env::var("BUILD").unwrap()); config.hosts.push(config.build.clone()); for host in build.host.iter() { let host = INTERNER.intern_str(host); @@ -539,22 +550,12 @@ impl Config { set(&mut config.rust_dist_src, t.src_tarball); } - let out = env::var_os("BUILD_DIR").map(PathBuf::from).expect("'BUILD_DIR' set"); - config.out = out.clone(); - - let stage0_root = out.join(&config.build).join("stage0/bin"); - config.initial_rustc = match build.rustc { - Some(s) => PathBuf::from(s), - None => stage0_root.join(exe("rustc", &config.build)), - }; - config.initial_cargo = match build.cargo { - Some(s) => PathBuf::from(s), - None => stage0_root.join(exe("cargo", &config.build)), - }; - // Now that we've reached the end of our configuration, infer the // default values for all options that we haven't otherwise stored yet. + set(&mut config.initial_rustc, build.rustc.map(PathBuf::from)); + set(&mut config.initial_rustc, build.cargo.map(PathBuf::from)); + let default = false; config.llvm_assertions = llvm_assertions.unwrap_or(default); From 42fde21c27c67ce3c665e344b602cfd1d22842cc Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 10 Mar 2018 07:03:06 -0700 Subject: [PATCH 07/13] Add tests to rustbuild In order to run tests, previous commits have cfg'd out various parts of rustbuild. Generally speaking, these are filesystem-related operations and process-spawning related parts. Then, rustbuild is run "as normal" and the various steps that where run are retrieved from the cache and checked against the expected results. Note that this means that the current implementation primarily tests "what" we build, but doesn't actually test that what we build *will* build. In other words, it doesn't do any form of dependency verification for any crate. This is possible to implement, but is considered future work. This implementation strives to cfg out as little code as possible; it also does not currently test anywhere near all of rustbuild. The current tests are also not checked for "correctness," rather, they simply represent what we do as of this commit, which may be wrong. Test cases are drawn from the old implementation of rustbuild, though the expected results may vary. --- src/Cargo.lock | 17 ++ src/bootstrap/Cargo.toml | 3 + src/bootstrap/builder.rs | 479 ++++++++++++++++++++++++++++++++++++++- src/bootstrap/cache.rs | 12 + src/bootstrap/lib.rs | 4 + src/bootstrap/test.rs | 1 + 6 files changed, 514 insertions(+), 2 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index e4c16b92ceba5..b76bbd372712e 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -124,6 +124,7 @@ dependencies = [ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -528,6 +529,11 @@ name = "diff" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "dlmalloc" version = "0.0.0" @@ -1233,6 +1239,15 @@ name = "pkg-config" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pretty_assertions" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "0.2.3" @@ -2683,6 +2698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961" "checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" +"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834" @@ -2755,6 +2771,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" "checksum pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab94faafeb93f4c5e3ce81ca0e5a779529a602ad5d09ae6d21996bfb8b6a52bf" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" "checksum proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "388d7ea47318c5ccdeb9ba6312cee7d3f65dd2804be8580a170fce410d50b786" "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 2d47834131784..c09a3d865230f 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -42,3 +42,6 @@ serde_json = "1.0.2" toml = "0.4" lazy_static = "0.2" time = "0.1" + +[dev-dependencies] +pretty_assertions = "0.5" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index c2a53e4590e78..80136aa86e3e2 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -401,12 +401,16 @@ impl<'a> Builder<'a> { } pub fn execute_cli(&self) { - StepDescription::run(&Builder::get_step_descriptions(self.kind), self, &self.paths); + self.run_step_descriptions(&Builder::get_step_descriptions(self.kind), &self.paths); } pub fn default_doc(&self, paths: Option<&[PathBuf]>) { let paths = paths.unwrap_or(&[]); - StepDescription::run(&Builder::get_step_descriptions(Kind::Doc), self, paths); + self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths); + } + + fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) { + StepDescription::run(v, self, paths); } /// Obtain a compiler at a given stage and for a given host. Explicitly does @@ -862,3 +866,474 @@ impl<'a> Builder<'a> { out } } + +#[cfg(test)] +mod __test { + use config::Config; + use super::*; + + fn configure(host: &[&str], target: &[&str]) -> Config { + let mut config = Config::default_opts(); + config.run_host_only = true; + config.build = INTERNER.intern_str("A"); + config.hosts = vec![config.build].clone().into_iter() + .chain(host.iter().map(|s| INTERNER.intern_str(s))).collect::>(); + config.targets = config.hosts.clone().into_iter() + .chain(target.iter().map(|s| INTERNER.intern_str(s))).collect::>(); + config + } + + fn first(v: Vec<(A, B)>) -> Vec { + v.into_iter().map(|(a, _)| a).collect::>() + } + + #[test] + fn dist_baseline() { + let build = Build::new(configure(&[], &[])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + + assert_eq!(first(builder.cache.all::()), &[ + dist::Docs { stage: 2, host: a }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Mingw { host: a }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + ]); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); + } + + #[test] + fn dist_with_targets() { + let build = Build::new(configure(&[], &["B"])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + + assert_eq!(first(builder.cache.all::()), &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ]); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); + } + + #[test] + fn dist_with_hosts() { + let build = Build::new(configure(&["B"], &[])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + + assert_eq!(first(builder.cache.all::()), &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, + dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ]); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); + } + + #[test] + fn dist_with_targets_and_hosts() { + let build = Build::new(configure(&["B"], &["C"])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); + + assert_eq!(first(builder.cache.all::()), &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + dist::Docs { stage: 2, host: c }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + dist::Mingw { host: c }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, + dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + ]); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); + } + + #[test] + fn dist_with_target_flag() { + let mut config = configure(&["B"], &["C"]); + config.run_host_only = false; // as-if --target=C was passed + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); + + assert_eq!(first(builder.cache.all::()), &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + dist::Docs { stage: 2, host: c }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + dist::Mingw { host: c }, + ]); + assert_eq!(first(builder.cache.all::()), &[]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + ]); + assert_eq!(first(builder.cache.all::()), &[]); + } + + #[test] + fn dist_with_same_targets_and_hosts() { + let build = Build::new(configure(&["B"], &["B"])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + + assert_eq!(first(builder.cache.all::()), &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, + dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ]); + assert_eq!(first(builder.cache.all::()), &[dist::Src]); + assert_eq!(first(builder.cache.all::()), &[ + compile::Std { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + compile::Assemble { + target_compiler: Compiler { host: a, stage: 0 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 2 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 2 }, + }, + ]); + } + + #[test] + fn build_default() { + let build = Build::new(configure(&["B"], &["C"])); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); + + assert!(!builder.cache.all::().is_empty()); + assert!(!builder.cache.all::().is_empty()); + assert_eq!(first(builder.cache.all::()), &[ + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + ]); + + assert_eq!(first(builder.cache.all::()), &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ]); + } + + #[test] + fn build_with_target_flag() { + let mut config = configure(&["B"], &["C"]); + config.run_host_only = false; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = INTERNER.intern_str("A"); + let b = INTERNER.intern_str("B"); + let c = INTERNER.intern_str("C"); + + assert!(!builder.cache.all::().is_empty()); + assert_eq!(first(builder.cache.all::()), &[ + compile::Assemble { + target_compiler: Compiler { host: a, stage: 0 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 2 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 2 }, + }, + ]); + assert_eq!(first(builder.cache.all::()), &[ + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + ]); + + assert_eq!(first(builder.cache.all::()), &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ]); + } +} diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index cbc77ab5bf42e..d81c6bc28e527 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -278,4 +278,16 @@ impl Cache { .expect("invalid type mapped"); stepcache.get(step).cloned() } + + #[cfg(test)] + pub fn all(&mut self) -> Vec<(S, S::Output)> { + let cache = self.0.get_mut(); + let type_id = TypeId::of::(); + let mut v = cache.remove(&type_id) + .map(|b| b.downcast::>().expect("correct type")) + .map(|m| m.into_iter().collect::>()) + .unwrap_or_default(); + v.sort_by_key(|&(a, _)| a); + v + } } diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index cb3a9dfbf3c11..b7c8150a7dab9 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -132,6 +132,10 @@ extern crate num_cpus; extern crate toml; extern crate time; +#[cfg(test)] +#[macro_use] +extern crate pretty_assertions; + #[cfg(unix)] extern crate libc; diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 76f1a4efbf014..0b70a50f67d57 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1692,6 +1692,7 @@ impl Step for Bootstrap { let mut cmd = Command::new(&build.initial_cargo); cmd.arg("test") .current_dir(build.src.join("src/bootstrap")) + .env("RUSTFLAGS", "-Cdebuginfo=2") .env("CARGO_TARGET_DIR", build.out.join("bootstrap")) .env("RUSTC_BOOTSTRAP", "1") .env("RUSTC", &build.initial_rustc); From f4620a3d1471fd7943ebd413dcbc94d51bcfea8e Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Thu, 15 Mar 2018 17:29:53 -0600 Subject: [PATCH 08/13] Stub out less code --- src/bootstrap/builder.rs | 4 +++- src/bootstrap/compile.rs | 1 - src/bootstrap/doc.rs | 1 - src/bootstrap/lib.rs | 28 +++++++++++++--------------- src/bootstrap/tool.rs | 6 +----- src/bootstrap/util.rs | 2 -- 6 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 80136aa86e3e2..49d4864190aee 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -691,7 +691,7 @@ impl<'a> Builder<'a> { // the options through environment variables that are fetched and understood by both. // // FIXME: the guard against msvc shouldn't need to be here - if !target.contains("msvc") && !cfg!(test) { + if !target.contains("msvc") { let ccache = self.config.ccache.as_ref(); let ccacheify = |s: &Path| { let ccache = match ccache { @@ -874,6 +874,8 @@ mod __test { fn configure(host: &[&str], target: &[&str]) -> Config { let mut config = Config::default_opts(); + // don't save toolstates + config.save_toolstates = None; config.run_host_only = true; config.build = INTERNER.intern_str("A"); config.hosts = vec![config.build].clone().into_iter() diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index d1a6a8d12a7c3..daf25a36d4774 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -722,7 +722,6 @@ impl Step for CodegenBackend { fn copy_codegen_backends_to_sysroot(builder: &Builder, compiler: Compiler, target_compiler: Compiler) { - if cfg!(test) { return; } let build = builder.build; let target = target_compiler.host; diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 5f3d9ecfc042d..44073a5b07572 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -817,7 +817,6 @@ impl Step for UnstableBookGen { } fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> { - if cfg!(test) { return Ok(()); } if let Ok(m) = fs::symlink_metadata(dst) { if m.file_type().is_dir() { try!(fs::remove_dir_all(dst)); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b7c8150a7dab9..fca265fe41c26 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -367,20 +367,20 @@ impl Build { cc_detect::find(&mut build); build.verbose("running sanity check"); sanity::check(&mut build); - if !cfg!(test) { - // If local-rust is the same major.minor as the current version, then force a - // local-rebuild - let local_version_verbose = output( - Command::new(&build.initial_rustc).arg("--version").arg("--verbose")); - let local_release = local_version_verbose - .lines().filter(|x| x.starts_with("release:")) - .next().unwrap().trim_left_matches("release:").trim(); - let my_version = channel::CFG_RELEASE_NUM; - if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { - build.verbose(&format!("auto-detected local-rebuild {}", local_release)); - build.local_rebuild = true; - } + + // If local-rust is the same major.minor as the current version, then force a + // local-rebuild + let local_version_verbose = output( + Command::new(&build.initial_rustc).arg("--version").arg("--verbose")); + let local_release = local_version_verbose + .lines().filter(|x| x.starts_with("release:")) + .next().unwrap().trim_left_matches("release:").trim(); + let my_version = channel::CFG_RELEASE_NUM; + if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { + build.verbose(&format!("auto-detected local-rebuild {}", local_release)); + build.local_rebuild = true; } + build.verbose("learning about cargo"); metadata::build(&mut build); @@ -426,7 +426,6 @@ impl Build { /// /// After this executes, it will also ensure that `dir` exists. fn clear_if_dirty(&self, dir: &Path, input: &Path) -> bool { - if cfg!(test) { return true; } let stamp = dir.join(".stamp"); let mut cleared = false; if mtime(&stamp) < mtime(input) { @@ -697,7 +696,6 @@ impl Build { /// Returns the path to the linker for the given target if it needs to be overridden. fn linker(&self, target: Interned) -> Option<&Path> { - if cfg!(test) { return None; } if let Some(linker) = self.config.target_config.get(&target) .and_then(|c| c.linker.as_ref()) { Some(linker) diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 362ec0c3b5085..2bb46cc5171d6 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -199,11 +199,7 @@ impl Step for ToolBuild { if !is_expected { if !is_ext_tool { - if cfg!(test) { - panic!("unexpected failure -- would have hard exited"); - } else { - exit(1); - } + exit(1); } else { return None; } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 99d0548a05e7f..f3f4278d32901 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -34,7 +34,6 @@ pub fn staticlib(name: &str, target: &str) -> String { /// Copies a file from `src` to `dst` pub fn copy(src: &Path, dst: &Path) { - if cfg!(test) { 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. @@ -67,7 +66,6 @@ pub fn replace_in_file(path: &Path, replacements: &[(&str, &str)]) { } pub fn read_stamp_file(stamp: &Path) -> Vec { - if cfg!(test) { return vec![]; } let mut paths = Vec::new(); let mut contents = Vec::new(); t!(t!(File::open(stamp)).read_to_end(&mut contents)); From b0dbc7c15d4f3027410b3836154da1ae63e0a7d3 Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Tue, 27 Mar 2018 12:44:33 +0200 Subject: [PATCH 09/13] Implement generating graphs of the build steps --- src/Cargo.lock | 23 +++++++++++++++++++++++ src/bootstrap/Cargo.toml | 1 + src/bootstrap/builder.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/bootstrap/lib.rs | 9 +++++---- 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index b76bbd372712e..5b918a063b07c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -124,6 +124,7 @@ dependencies = [ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", @@ -641,6 +642,11 @@ version = "0.1.0" name = "find_impls" version = "0.1.0" +[[package]] +name = "fixedbitset" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "flate2" version = "1.0.1" @@ -1168,6 +1174,11 @@ dependencies = [ "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ordermap" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "owning_ref" version = "0.3.3" @@ -1234,6 +1245,15 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "petgraph" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pkg-config" version = "0.3.9" @@ -2709,6 +2729,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f" +"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" @@ -2764,12 +2785,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1636c9f1d78af9cbcc50e523bfff4a30274108aad5e86761afd4d31e4e184fa7" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdc5c4a02e69ce65046f1763a0181107038e02176233acb0b3351d7cc588f9" +"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd" "checksum parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "538ef00b7317875071d5e00f603f24d16f0b474c1a5fc0ccb8b454ca72eafa79" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" "checksum pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab94faafeb93f4c5e3ce81ca0e5a779529a602ad5d09ae6d21996bfb8b6a52bf" +"checksum petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8b30dc85588cd02b9b76f5e386535db546d21dc68506cff2abebee0b6445e8e4" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index c09a3d865230f..2f9c4e148a6ba 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -42,6 +42,7 @@ serde_json = "1.0.2" toml = "0.4" lazy_static = "0.2" time = "0.1" +petgraph = "0.4.12" [dev-dependencies] pretty_assertions = "0.5" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 49d4864190aee..86a51c8e26bb8 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -19,6 +19,7 @@ use std::ops::Deref; use std::path::{Path, PathBuf}; use std::process::Command; use std::time::{Instant, Duration}; +use std::collections::HashMap; use compile; use install; @@ -35,6 +36,9 @@ use native; pub use Compiler; +use petgraph::Graph; +use petgraph::graph::NodeIndex; + pub struct Builder<'a> { pub build: &'a Build, pub top_stage: u32, @@ -43,6 +47,9 @@ pub struct Builder<'a> { stack: RefCell>>, time_spent_on_dependencies: Cell, pub paths: Vec, + graph_nodes: RefCell>, + graph: RefCell>, + parent: Cell>, } impl<'a> Deref for Builder<'a> { @@ -353,6 +360,9 @@ impl<'a> Builder<'a> { stack: RefCell::new(Vec::new()), time_spent_on_dependencies: Cell::new(Duration::new(0, 0)), paths: vec![], + graph_nodes: RefCell::new(HashMap::new()), + graph: RefCell::new(Graph::new()), + parent: Cell::new(None), }; let builder = &builder; @@ -389,6 +399,9 @@ impl<'a> Builder<'a> { stack: RefCell::new(Vec::new()), time_spent_on_dependencies: Cell::new(Duration::new(0, 0)), paths: paths.to_owned(), + graph_nodes: RefCell::new(HashMap::new()), + graph: RefCell::new(Graph::new()), + parent: Cell::new(None), }; if kind == Kind::Dist { @@ -833,12 +846,37 @@ impl<'a> Builder<'a> { if let Some(out) = self.cache.get(&step) { self.build.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step)); + { + let mut graph = self.graph.borrow_mut(); + let parent = self.parent.get(); + let us = *self.graph_nodes.borrow_mut() + .entry(format!("{:?}", step)) + .or_insert_with(|| graph.add_node(format!("{:?}", step))); + if let Some(parent) = parent { + graph.add_edge(parent, us, false); + } + } + return out; } self.build.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step)); stack.push(Box::new(step.clone())); } + let prev_parent = self.parent.get(); + + { + let mut graph = self.graph.borrow_mut(); + let parent = self.parent.get(); + let us = *self.graph_nodes.borrow_mut() + .entry(format!("{:?}", step)) + .or_insert_with(|| graph.add_node(format!("{:?}", step))); + self.parent.set(Some(us)); + if let Some(parent) = parent { + graph.add_edge(parent, us, true); + } + } + let (out, dur) = { let start = Instant::now(); let zero = Duration::new(0, 0); @@ -849,6 +887,8 @@ impl<'a> Builder<'a> { (out, dur - deps) }; + self.parent.set(prev_parent); + if self.build.config.print_step_timings && dur > Duration::from_millis(100) { println!("[TIMING] {:?} -- {}.{:03}", step, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index fca265fe41c26..5b13fa27fbfbe 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -131,6 +131,7 @@ extern crate getopts; extern crate num_cpus; extern crate toml; extern crate time; +extern crate petgraph; #[cfg(test)] #[macro_use] @@ -600,14 +601,14 @@ impl Build { /// Runs a command, printing out nice contextual information if it fails. fn run(&self, cmd: &mut Command) { - if cfg!(test) { return; } + if self.config.dry_run { return; } self.verbose(&format!("running: {:?}", cmd)); run_silent(cmd) } /// Runs a command, printing out nice contextual information if it fails. fn run_quiet(&self, cmd: &mut Command) { - if cfg!(test) { return; } + if self.config.dry_run { return; } self.verbose(&format!("running: {:?}", cmd)); run_suppressed(cmd) } @@ -616,7 +617,7 @@ impl Build { /// Exits if the command failed to execute at all, otherwise returns its /// `status.success()`. fn try_run(&self, cmd: &mut Command) -> bool { - if cfg!(test) { return true; } + if self.config.dry_run { return true; } self.verbose(&format!("running: {:?}", cmd)); try_run_silent(cmd) } @@ -625,7 +626,7 @@ impl Build { /// Exits if the command failed to execute at all, otherwise returns its /// `status.success()`. fn try_run_quiet(&self, cmd: &mut Command) -> bool { - if cfg!(test) { return true; } + if self.config.dry_run { return true; } self.verbose(&format!("running: {:?}", cmd)); try_run_suppressed(cmd) } From a727447f5927ac0a186af4504f8a11014f42b1da Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Tue, 27 Mar 2018 16:06:47 +0200 Subject: [PATCH 10/13] 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. --- src/bootstrap/builder.rs | 10 +- src/bootstrap/check.rs | 6 +- src/bootstrap/compile.rs | 49 ++++---- src/bootstrap/config.rs | 10 +- src/bootstrap/dist.rs | 236 +++++++++++++++++---------------------- src/bootstrap/doc.rs | 35 +++--- src/bootstrap/flags.rs | 4 +- src/bootstrap/lib.rs | 201 +++++++++++++++++++++++++++++++-- src/bootstrap/native.rs | 14 ++- src/bootstrap/test.rs | 9 +- src/bootstrap/tool.rs | 6 +- src/bootstrap/util.rs | 106 +----------------- 12 files changed, 393 insertions(+), 293 deletions(-) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 86a51c8e26bb8..3f5ec4933d02b 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -413,8 +413,9 @@ impl<'a> Builder<'a> { builder } - pub fn execute_cli(&self) { + pub fn execute_cli(&self) -> Graph { 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::>(); diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index a9dccea827b6e..a39fad67ebea4 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -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)); } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index daf25a36d4774..872c29085289a 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -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, 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 { + 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") diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 0848590a9bc10..76672df5c570d 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -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, 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()); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index cfa0cdecca6b3..86ef5c35cd7f4 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -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, &[("", &month_year), ("", 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())); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 44073a5b07572..eeea6f0d01d2a 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -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) } diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 60b22e35832f9..cd304fb26e0bf 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -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, pub rustc_error_format: Option, + pub dry_run: bool, } pub enum Subcommand { @@ -112,6 +112,7 @@ To learn more about a subcommand, run `./x.py -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()), diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 5b13fa27fbfbe..7b37c9cefa5cb 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -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::>(), + act_graph.raw_nodes().iter().map(|i| &i.weight).collect::>()); + assert_eq!(dry_graph.raw_edges() + .iter().map(|i| (&dry_graph[i.source()], &dry_graph[i.target()], &i.weight)) + .collect::>(), + act_graph.raw_edges() + .iter().map(|i| (&act_graph[i.source()], &act_graph[i.target()], &i.weight)) + .collect::>()); + } 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,7 +1022,167 @@ impl Build { } ret } + + fn read_stamp_file(&self, stamp: &Path) -> Vec { + 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 { + 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::>().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 { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index f95f8e01dae50..c49811d839a04 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -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; diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 0b70a50f67d57..2fb84db4d897e 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -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 diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 2bb46cc5171d6..0b1616b9b4f90 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -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 diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index f3f4278d32901..8a64b07496c96 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -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 { - 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); From 545b92f46d98bf5c812343315025bfb92f37837f Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Wed, 28 Mar 2018 17:25:09 +0200 Subject: [PATCH 11/13] Avoid printing output when in dry run mode --- src/bootstrap/compile.rs | 38 +++++++++++++++---------------- src/bootstrap/dist.rs | 36 ++++++++++++++--------------- src/bootstrap/doc.rs | 24 ++++++++++---------- src/bootstrap/install.rs | 7 +++--- src/bootstrap/lib.rs | 7 +++++- src/bootstrap/native.rs | 16 ++++++------- src/bootstrap/test.rs | 49 ++++++++++++++++++++-------------------- src/bootstrap/tool.rs | 5 ++-- src/bootstrap/util.rs | 17 ++++++++------ 9 files changed, 105 insertions(+), 94 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 872c29085289a..da57881202d17 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -77,7 +77,7 @@ impl Step for Std { compiler: from, target, }); - println!("Uplifting stage1 std ({} -> {})", from.host, target); + builder.info(&format!("Uplifting stage1 std ({} -> {})", from.host, target)); // Even if we're not building std this stage, the new sysroot must // still contain the musl startup objects. @@ -105,8 +105,8 @@ impl Step for Std { std_cargo(builder, &compiler, target, &mut cargo); let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage)); - println!("Building stage{} std artifacts ({} -> {})", compiler.stage, - &compiler.host, target); + build.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage, + &compiler.host, target)); run_cargo(build, &mut cargo, &libstd_stamp(build, compiler, target), @@ -213,12 +213,12 @@ impl Step for StdLink { let compiler = self.compiler; let target_compiler = self.target_compiler; let target = self.target; - println!("Copying stage{} std from stage{} ({} -> {} / {})", + build.info(&format!("Copying stage{} std from stage{} ({} -> {} / {})", target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, - target); + target)); let libdir = builder.sysroot_libdir(target_compiler, target); add_to_sysroot(&build, &libdir, &libstd_stamp(build, compiler, target)); @@ -352,7 +352,7 @@ impl Step for Test { compiler: builder.compiler(1, build.build), target, }); - println!("Uplifting stage1 test ({} -> {})", &build.build, target); + build.info(&format!("Uplifting stage1 test ({} -> {})", &build.build, target)); builder.ensure(TestLink { compiler: builder.compiler(1, build.build), target_compiler: compiler, @@ -367,8 +367,8 @@ impl Step for Test { test_cargo(build, &compiler, target, &mut cargo); let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage)); - println!("Building stage{} test artifacts ({} -> {})", compiler.stage, - &compiler.host, target); + build.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage, + &compiler.host, target)); run_cargo(build, &mut cargo, &libtest_stamp(build, compiler, target), @@ -414,12 +414,12 @@ impl Step for TestLink { let compiler = self.compiler; let target_compiler = self.target_compiler; let target = self.target; - println!("Copying stage{} test from stage{} ({} -> {} / {})", + build.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})", target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, - target); + target)); add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target), &libtest_stamp(build, compiler, target)); builder.ensure(tool::CleanTools { @@ -469,7 +469,7 @@ impl Step for Rustc { compiler: builder.compiler(1, build.build), target, }); - println!("Uplifting stage1 rustc ({} -> {})", &build.build, target); + build.info(&format!("Uplifting stage1 rustc ({} -> {})", &build.build, target)); builder.ensure(RustcLink { compiler: builder.compiler(1, build.build), target_compiler: compiler, @@ -491,8 +491,8 @@ impl Step for Rustc { rustc_cargo(build, &mut cargo); let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage)); - println!("Building stage{} compiler artifacts ({} -> {})", - compiler.stage, &compiler.host, target); + build.info(&format!("Building stage{} compiler artifacts ({} -> {})", + compiler.stage, &compiler.host, target)); run_cargo(build, &mut cargo, &librustc_stamp(build, compiler, target), @@ -569,12 +569,12 @@ impl Step for RustcLink { let compiler = self.compiler; let target_compiler = self.target_compiler; let target = self.target; - println!("Copying stage{} rustc from stage{} ({} -> {} / {})", + build.info(&format!("Copying stage{} rustc from stage{} ({} -> {} / {})", target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, - target); + target)); add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target), &librustc_stamp(build, compiler, target)); builder.ensure(tool::CleanTools { @@ -648,8 +648,8 @@ impl Step for CodegenBackend { features.push_str(" emscripten"); } - println!("Building stage{} codegen artifacts ({} -> {}, {})", - compiler.stage, &compiler.host, target, self.backend); + build.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})", + compiler.stage, &compiler.host, target, self.backend)); // Pass down configuration from the LLVM build into the build of // librustc_llvm and librustc_trans. @@ -933,7 +933,7 @@ impl Step for Assemble { let stage = target_compiler.stage; let host = target_compiler.host; - println!("Assembling stage{} compiler ({})", stage, host); + build.info(&format!("Assembling stage{} compiler ({})", stage, host)); // Link in all dylibs to the libdir let sysroot = builder.sysroot(target_compiler); @@ -1186,7 +1186,7 @@ pub fn stream_cargo( // Make sure Cargo actually succeeded after we read all of its stdout. let status = t!(child.wait()); if !status.success() { - println!("command did not execute successfully: {:?}\n\ + eprintln!("command did not execute successfully: {:?}\n\ expected success, got: {}", cargo, status); diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 86ef5c35cd7f4..774f4e6e8bf25 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -89,9 +89,9 @@ impl Step for Docs { let name = pkgname(build, "rust-docs"); - println!("Dist docs ({})", host); + build.info(&format!("Dist docs ({})", host)); if !build.config.docs { - println!("\tskipping - docs disabled"); + build.info(&format!("\tskipping - docs disabled")); return distdir(build).join(format!("{}-{}.tar.gz", name, host)); } @@ -152,9 +152,9 @@ impl Step for RustcDocs { let name = pkgname(build, "rustc-docs"); - println!("Dist compiler docs ({})", host); + build.info(&format!("Dist compiler docs ({})", host)); if !build.config.compiler_docs { - println!("\tskipping - compiler docs disabled"); + build.info(&format!("\tskipping - compiler docs disabled")); return distdir(build).join(format!("{}-{}.tar.gz", name, host)); } @@ -343,7 +343,7 @@ impl Step for Mingw { return None; } - println!("Dist mingw ({})", host); + build.info(&format!("Dist mingw ({})", host)); let name = pkgname(build, "rust-mingw"); let image = tmpdir(build).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); @@ -398,7 +398,7 @@ impl Step for Rustc { let compiler = self.compiler; let host = self.compiler.host; - println!("Dist rustc stage{} ({})", compiler.stage, compiler.host); + build.info(&format!("Dist rustc stage{} ({})", compiler.stage, compiler.host)); let name = pkgname(build, "rustc"); let image = tmpdir(build).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); @@ -627,12 +627,12 @@ impl Step for Std { let target = self.target; let name = pkgname(build, "rust-std"); - println!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target); + build.info(&format!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target)); // The only true set of target libraries came from the build triple, so // let's reduce redundant work by only producing archives from that host. if compiler.host != build.build { - println!("\tskipping, not a build host"); + build.info(&format!("\tskipping, not a build host")); return distdir(build).join(format!("{}-{}.tar.gz", name, target)); } @@ -704,11 +704,11 @@ impl Step for Analysis { let compiler = self.compiler; let target = self.target; assert!(build.config.extended); - println!("Dist analysis"); + build.info(&format!("Dist analysis")); let name = pkgname(build, "rust-analysis"); if &compiler.host != build.build { - println!("\tskipping, not a build host"); + build.info(&format!("\tskipping, not a build host")); return distdir(build).join(format!("{}-{}.tar.gz", name, target)); } @@ -730,7 +730,7 @@ impl Step for Analysis { let image_src = src.join("save-analysis"); let dst = image.join("lib/rustlib").join(target).join("analysis"); t!(fs::create_dir_all(&dst)); - println!("image_src: {:?}, dst: {:?}", image_src, dst); + build.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst)); build.cp_r(&image_src, &dst); let mut cmd = rust_installer(builder); @@ -813,7 +813,7 @@ impl Step for Src { /// Creates the `rust-src` installer component fn run(self, builder: &Builder) -> PathBuf { let build = builder.build; - println!("Dist src"); + build.info(&format!("Dist src")); let name = pkgname(build, "rust-src"); let image = tmpdir(build).join(format!("{}-image", name)); @@ -908,7 +908,7 @@ impl Step for PlainSourceTarball { /// Creates the plain source tarball fn run(self, builder: &Builder) -> PathBuf { let build = builder.build; - println!("Create plain source tarball"); + build.info(&format!("Create plain source tarball")); // Make sure that the root folder of tarball has the correct name let plain_name = format!("{}-src", pkgname(build, "rustc")); @@ -985,7 +985,7 @@ impl Step for PlainSourceTarball { if let Some(dir) = tarball.parent() { build.create_dir(&dir); } - println!("running installer"); + build.info(&format!("running installer")); let mut cmd = rust_installer(builder); cmd.arg("tarball") .arg("--input").arg(&plain_name) @@ -1042,7 +1042,7 @@ impl Step for Cargo { let stage = self.stage; let target = self.target; - println!("Dist cargo stage{} ({})", stage, target); + build.info(&format!("Dist cargo stage{} ({})", stage, target)); let src = build.src.join("src/tools/cargo"); let etc = src.join("src/etc"); let release_num = build.release_num("cargo"); @@ -1130,7 +1130,7 @@ impl Step for Rls { let target = self.target; assert!(build.config.extended); - println!("Dist RLS stage{} ({})", stage, target); + build.info(&format!("Dist RLS stage{} ({})", stage, target)); let src = build.src.join("src/tools/rls"); let release_num = build.release_num("rls"); let name = pkgname(build, "rls"); @@ -1210,7 +1210,7 @@ impl Step for Rustfmt { let stage = self.stage; let target = self.target; - println!("Dist Rustfmt stage{} ({})", stage, target); + build.info(&format!("Dist Rustfmt stage{} ({})", stage, target)); let src = build.src.join("src/tools/rustfmt"); let release_num = build.release_num("rustfmt"); let name = pkgname(build, "rustfmt"); @@ -1297,7 +1297,7 @@ impl Step for Extended { let stage = self.stage; let target = self.target; - println!("Dist extended stage{} ({})", stage, target); + build.info(&format!("Dist extended stage{} ({})", stage, target)); let rustc_installer = builder.ensure(Rustc { compiler: builder.compiler(stage, target), diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index eeea6f0d01d2a..f07c3e707574b 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -169,7 +169,7 @@ impl Step for CargoBook { let out = out.join(name); - println!("Cargo Book ({}) - {}", target, name); + build.info(&format!("Cargo Book ({}) - {}", target, name)); let _ = fs::remove_dir_all(&out); @@ -215,7 +215,7 @@ impl Step for RustbookSrc { if up_to_date(&src, &index) && up_to_date(&rustbook, &index) { return } - println!("Rustbook ({}) - {}", target, name); + build.info(&format!("Rustbook ({}) - {}", target, name)); let _ = fs::remove_dir_all(&out); build.run(rustbook_cmd .arg("build") @@ -283,11 +283,11 @@ impl Step for TheBook { // build the index page let index = format!("{}/index.md", name); - println!("Documenting book index ({})", target); + build.info(&format!("Documenting book index ({})", target)); invoke_rustdoc(builder, compiler, target, &index); // build the redirect pages - println!("Documenting book redirect pages ({})", target); + build.info(&format!("Documenting book redirect pages ({})", target)); for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) { let file = t!(file); let path = file.path(); @@ -360,7 +360,7 @@ impl Step for Standalone { let build = builder.build; let target = self.target; let compiler = self.compiler; - println!("Documenting standalone ({})", target); + build.info(&format!("Documenting standalone ({})", target)); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); @@ -451,7 +451,7 @@ impl Step for Std { let build = builder.build; let stage = self.stage; let target = self.target; - println!("Documenting stage{} std ({})", stage, target); + build.info(&format!("Documenting stage{} std ({})", stage, target)); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); let compiler = builder.compiler(stage, build.build); @@ -532,7 +532,7 @@ impl Step for Test { let build = builder.build; let stage = self.stage; let target = self.target; - println!("Documenting stage{} test ({})", stage, target); + build.info(&format!("Documenting stage{} test ({})", stage, target)); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); let compiler = builder.compiler(stage, build.build); @@ -598,7 +598,7 @@ impl Step for WhitelistedRustc { let build = builder.build; let stage = self.stage; let target = self.target; - println!("Documenting stage{} whitelisted compiler ({})", stage, target); + build.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target)); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); let compiler = builder.compiler(stage, build.build); @@ -670,7 +670,7 @@ impl Step for Rustc { let build = builder.build; let stage = self.stage; let target = self.target; - println!("Documenting stage{} compiler ({})", stage, target); + build.info(&format!("Documenting stage{} compiler ({})", stage, target)); let out = build.compiler_doc_out(target); t!(fs::create_dir_all(&out)); let compiler = builder.compiler(stage, build.build); @@ -682,7 +682,7 @@ impl Step for Rustc { }; if !build.config.compiler_docs { - println!("\tskipping - compiler docs disabled"); + build.info(&format!("\tskipping - compiler docs disabled")); return; } @@ -761,7 +761,7 @@ impl Step for ErrorIndex { let build = builder.build; let target = self.target; - println!("Documenting error index ({})", target); + build.info(&format!("Documenting error index ({})", target)); let out = build.doc_out(target); t!(fs::create_dir_all(&out)); let mut index = builder.tool_cmd(Tool::ErrorIndex); @@ -806,7 +806,7 @@ impl Step for UnstableBookGen { target, }); - println!("Generating unstable book md files ({})", target); + build.info(&format!("Generating unstable book md files ({})", target)); let out = build.md_doc_out(target).join("unstable-book"); build.create_dir(&out); build.remove_dir(&out); diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 0d7c1b8de6323..4b05cac1ce697 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -63,7 +63,7 @@ fn install_sh( host: Option> ) { let build = builder.build; - println!("Install {} stage{} ({:?})", package, stage, host); + build.info(&format!("Install {} stage{} ({:?})", package, stage, host)); let prefix_default = PathBuf::from("/usr/local"); let sysconfdir_default = PathBuf::from("/etc"); @@ -212,7 +212,7 @@ install!((self, builder, _config), Self::should_install(builder) { install_rls(builder, self.stage, self.target); } else { - println!("skipping Install RLS stage{} ({})", self.stage, self.target); + builder.info(&format!("skipping Install RLS stage{} ({})", self.stage, self.target)); } }; Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, { @@ -220,7 +220,8 @@ install!((self, builder, _config), Self::should_install(builder) { install_rustfmt(builder, self.stage, self.target); } else { - println!("skipping Install Rustfmt stage{} ({})", self.stage, self.target); + builder.info( + &format!("skipping Install Rustfmt stage{} ({})", self.stage, self.target)); } }; Analysis, "analysis", Self::should_build(_config), only_hosts: false, { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 7b37c9cefa5cb..c677d78d07b1f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -667,6 +667,11 @@ impl Build { } } + fn info(&self, msg: &str) { + if self.config.dry_run { return; } + println!("{}", msg); + } + /// Returns the number of parallel jobs that have been configured for this /// build. fn jobs(&self) -> u32 { @@ -974,7 +979,7 @@ impl Build { pub fn fold_output(&self, name: F) -> Option where D: Into, F: FnOnce() -> D { - if self.ci_env == CiEnv::Travis { + if !self.config.dry_run && self.ci_env == CiEnv::Travis { Some(OutputFolder::new(name().into())) } else { None diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index c49811d839a04..c92d5c6f7ca49 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -106,8 +106,8 @@ impl Step for Llvm { let _folder = build.fold_output(|| "llvm"); let descriptor = if emscripten { "Emscripten " } else { "" }; - println!("Building {}LLVM for {}", descriptor, target); - let _time = util::timeit(); + build.info(&format!("Building {}LLVM for {}", descriptor, target)); + let _time = util::timeit(&build); t!(fs::create_dir_all(&out_dir)); // http://llvm.org/docs/CMake.html @@ -359,8 +359,8 @@ impl Step for Lld { } let _folder = build.fold_output(|| "lld"); - println!("Building LLD for {}", target); - let _time = util::timeit(); + build.info(&format!("Building LLD for {}", target)); + let _time = util::timeit(&build); t!(fs::create_dir_all(&out_dir)); let mut cfg = cmake::Config::new(build.src.join("src/tools/lld")); @@ -409,7 +409,7 @@ impl Step for TestHelpers { } let _folder = build.fold_output(|| "build_test_helpers"); - println!("Building test helpers"); + build.info(&format!("Building test helpers")); t!(fs::create_dir_all(&dst)); let mut cfg = cc::Build::new(); @@ -605,11 +605,11 @@ impl Step for Openssl { configure.arg("no-asm"); } configure.current_dir(&obj); - println!("Configuring openssl for {}", target); + build.info(&format!("Configuring openssl for {}", target)); build.run_quiet(&mut configure); - println!("Building openssl for {}", target); + build.info(&format!("Building openssl for {}", target)); build.run_quiet(Command::new("make").arg("-j1").current_dir(&obj)); - println!("Installing openssl for {}", target); + build.info(&format!("Installing openssl for {}", target)); build.run_quiet(Command::new("make").arg("install").arg("-j1").current_dir(&obj)); let mut f = t!(File::create(&stamp)); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 2fb84db4d897e..39740a83b0d0a 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -109,11 +109,11 @@ impl Step for Linkcheck { let build = builder.build; let host = self.host; - println!("Linkcheck ({})", host); + build.info(&format!("Linkcheck ({})", host)); builder.default_doc(None); - let _time = util::timeit(); + let _time = util::timeit(&build); try_run(build, builder.tool_cmd(Tool::Linkchecker) .arg(build.out.join(host).join("doc"))); } @@ -164,7 +164,7 @@ impl Step for Cargotest { let out_dir = build.out.join("ct"); t!(fs::create_dir_all(&out_dir)); - let _time = util::timeit(); + let _time = util::timeit(&build); let mut cmd = builder.tool_cmd(Tool::CargoTest); try_run(build, cmd.arg(&build.initial_cargo) .arg(&out_dir) @@ -509,7 +509,7 @@ impl Step for RustdocJS { }); builder.run(&mut command); } else { - println!("No nodejs found, skipping \"src/test/rustdoc-js\" tests"); + builder.info(&format!("No nodejs found, skipping \"src/test/rustdoc-js\" tests")); } } } @@ -541,7 +541,7 @@ impl Step for Tidy { } let _folder = build.fold_output(|| "tidy"); - println!("tidy check"); + builder.info(&format!("tidy check")); try_run(build, &mut cmd); } @@ -948,7 +948,8 @@ impl Step for Compiletest { } } if suite == "run-make-fulldeps" && !build.config.llvm_enabled { - println!("Ignoring run-make test suite as they generally don't work without LLVM"); + builder.info( + &format!("Ignoring run-make test suite as they generally don't work without LLVM")); return; } @@ -1002,9 +1003,9 @@ impl Step for Compiletest { build.ci_env.force_coloring_in_ci(&mut cmd); let _folder = build.fold_output(|| format!("test_{}", suite)); - println!("Check compiletest suite={} mode={} ({} -> {})", - suite, mode, &compiler.host, target); - let _time = util::timeit(); + builder.info(&format!("Check compiletest suite={} mode={} ({} -> {})", + suite, mode, &compiler.host, target)); + let _time = util::timeit(&build); try_run(build, &mut cmd); } } @@ -1039,7 +1040,7 @@ impl Step for DocTest { // Do a breadth-first traversal of the `src/doc` directory and just run // tests for all files that end in `*.md` let mut stack = vec![build.src.join(self.path)]; - let _time = util::timeit(); + let _time = util::timeit(&build); let _folder = build.fold_output(|| format!("test_{}", self.name)); let mut files = Vec::new(); @@ -1167,8 +1168,8 @@ impl Step for ErrorIndex { let _folder = build.fold_output(|| "test_error_index"); - println!("Testing error-index stage{}", compiler.stage); - let _time = util::timeit(); + build.info(&format!("Testing error-index stage{}", compiler.stage)); + let _time = util::timeit(&build); build.run(&mut tool); markdown_test(builder, compiler, &output); } @@ -1183,7 +1184,7 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool return true; } - println!("doc tests for: {}", markdown.display()); + build.info(&format!("doc tests for: {}", markdown.display())); let mut cmd = builder.rustdoc_cmd(compiler.host); build.add_rust_test_threads(&mut cmd); cmd.arg("--test"); @@ -1453,8 +1454,8 @@ impl Step for Crate { // The javascript shim implements the syscall interface so that test // output can be correctly reported. if !build.config.wasm_syscall { - println!("Libstd was built without `wasm_syscall` feature enabled: \ - test output may not be visible."); + build.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \ + test output may not be visible.")); } // On the wasm32-unknown-unknown target we're using LTO which is @@ -1476,9 +1477,9 @@ impl Step for Crate { let _folder = build.fold_output(|| { format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate) }); - println!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, - &compiler.host, target); - let _time = util::timeit(); + build.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, + &compiler.host, target)); + let _time = util::timeit(&build); try_run(build, &mut cargo); } } @@ -1543,9 +1544,9 @@ impl Step for CrateRustdoc { let _folder = build.fold_output(|| { format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage) }); - println!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, - &compiler.host, target); - let _time = util::timeit(); + build.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, + &compiler.host, target)); + let _time = util::timeit(&build); try_run(build, &mut cargo); } @@ -1592,7 +1593,7 @@ impl Step for RemoteCopyLibs { builder.ensure(compile::Test { compiler, target }); - println!("REMOTE copy libs to emulator ({})", target); + build.info(&format!("REMOTE copy libs to emulator ({})", target)); t!(fs::create_dir_all(build.out.join("tmp"))); let server = builder.ensure(tool::RemoteTestServer { compiler, target }); @@ -1640,7 +1641,7 @@ impl Step for Distcheck { fn run(self, builder: &Builder) { let build = builder.build; - println!("Distcheck"); + build.info(&format!("Distcheck")); let dir = build.out.join("tmp").join("distcheck"); let _ = fs::remove_dir_all(&dir); t!(fs::create_dir_all(&dir)); @@ -1664,7 +1665,7 @@ impl Step for Distcheck { .current_dir(&dir)); // Now make sure that rust-src has all of libstd's dependencies - println!("Distcheck rust-src"); + build.info(&format!("Distcheck rust-src")); let dir = build.out.join("tmp").join("distcheck-src"); let _ = fs::remove_dir_all(&dir); t!(fs::create_dir_all(&dir)); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 0b1616b9b4f90..93b6153fcb2f8 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -116,7 +116,7 @@ impl Step for ToolBuild { cargo.arg("--features").arg(self.extra_features.join(" ")); let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); - println!("Building stage{} tool {} ({})", compiler.stage, tool, target); + build.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target)); let mut duplicates = Vec::new(); let is_expected = compile::stream_cargo(build, &mut cargo, &mut |msg| { // Only care about big things like the RLS/Cargo for now @@ -427,7 +427,8 @@ impl Step for Rustdoc { .env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string()); let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage)); - println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host); + build.info(&format!("Building rustdoc for stage{} ({})", + target_compiler.stage, target_compiler.host)); build.run(&mut cargo); // Cargo adds a number of paths to the dylib search path on windows, which results in diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 8a64b07496c96..f8c7032369890 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -22,6 +22,7 @@ use std::process::Command; use std::time::{SystemTime, Instant}; use config::Config; +use Build; /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { @@ -100,19 +101,21 @@ pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf { buf } -pub struct TimeIt(Instant); +pub struct TimeIt(bool, Instant); /// Returns an RAII structure that prints out how long it took to drop. -pub fn timeit() -> TimeIt { - TimeIt(Instant::now()) +pub fn timeit(build: &Build) -> TimeIt { + TimeIt(build.config.dry_run, Instant::now()) } impl Drop for TimeIt { fn drop(&mut self) { - let time = self.0.elapsed(); - println!("\tfinished in {}.{:03}", - time.as_secs(), - time.subsec_nanos() / 1_000_000); + let time = self.1.elapsed(); + if !self.0 { + println!("\tfinished in {}.{:03}", + time.as_secs(), + time.subsec_nanos() / 1_000_000); + } } } From 0ce5cf06973aa75bc1729e5bc1aa0a611537014c Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sat, 31 Mar 2018 19:21:14 -0600 Subject: [PATCH 12/13] Fix a few accidental expectations --- src/bootstrap/dist.rs | 13 +++++++++---- src/bootstrap/lib.rs | 5 +++++ src/bootstrap/native.rs | 4 ++++ src/bootstrap/test.rs | 22 ++++++++++++++-------- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 774f4e6e8bf25..c9be17ff1ad2d 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -1480,7 +1480,7 @@ impl Step for Extended { 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"))); + build.remove(&exe.join(name).join("manifest.in")); }; prepare("rustc"); prepare("cargo"); @@ -1498,7 +1498,7 @@ impl Step for Extended { 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())); + build.create(&exe.join("LICENSE.txt"), &license); // Generate exe installer let mut cmd = Command::new("iscc"); @@ -1633,7 +1633,7 @@ impl Step for Extended { candle("GccGroup.wxs".as_ref()); } - t!(t!(File::create(exe.join("LICENSE.rtf"))).write_all(rtf.as_bytes())); + build.create(&exe.join("LICENSE.rtf"), &rtf); build.install(&etc.join("gfx/banner.bmp"), &exe, 0o644); build.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644); @@ -1665,7 +1665,9 @@ impl Step for Extended { build.run(&mut cmd); - t!(fs::rename(exe.join(&filename), distdir(build).join(&filename))); + if !build.config.dry_run { + t!(fs::rename(exe.join(&filename), distdir(build).join(&filename))); + } } } } @@ -1717,6 +1719,9 @@ impl Step for HashSign { fn run(self, builder: &Builder) { let build = builder.build; let mut cmd = builder.tool_cmd(Tool::BuildManifest); + if build.config.dry_run { + return; + } let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| { panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n") }); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index c677d78d07b1f..c76b6180749c9 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1178,6 +1178,11 @@ impl Build { }; iter.map(|e| t!(e)).collect::>().into_iter() } + + fn remove(&self, f: &Path) { + if self.config.dry_run { return; } + fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f)); + } } #[cfg(unix)] diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index c92d5c6f7ca49..db5891afd6b1f 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -235,6 +235,10 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) { return } + if build.config.dry_run { + return; + } + let mut cmd = Command::new(llvm_config); let version = output(cmd.arg("--version")); let mut parts = version.split('.').take(2) diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 39740a83b0d0a..c175d2c69016f 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -926,15 +926,17 @@ impl Step for Compiletest { target: build.config.build, emscripten: false, }); - let llvm_version = output(Command::new(&llvm_config).arg("--version")); - cmd.arg("--llvm-version").arg(llvm_version); + if !build.config.dry_run { + let llvm_version = output(Command::new(&llvm_config).arg("--version")); + cmd.arg("--llvm-version").arg(llvm_version); + } if !build.is_rust_llvm(target) { cmd.arg("--system-llvm"); } // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. - if suite == "run-make-fulldeps" { + if !build.config.dry_run && suite == "run-make-fulldeps" { let llvm_components = output(Command::new(&llvm_config).arg("--components")); let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); cmd.arg("--cc").arg(build.cc(target)) @@ -1177,11 +1179,15 @@ impl Step for ErrorIndex { fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool { let build = builder.build; - let mut file = t!(File::open(markdown)); - let mut contents = String::new(); - t!(file.read_to_string(&mut contents)); - if !contents.contains("```") { - return true; + match File::open(markdown) { + Ok(mut file) => { + let mut contents = String::new(); + t!(file.read_to_string(&mut contents)); + if !contents.contains("```") { + return true; + } + } + Err(_) => {}, } build.info(&format!("doc tests for: {}", markdown.display())); From 184d3bca6cc1ac2023bbd723223d1a9bd4d4380b Mon Sep 17 00:00:00 2001 From: Mark Simulacrum Date: Sun, 1 Apr 2018 10:51:24 -0600 Subject: [PATCH 13/13] Stop checking that the graph produced by a dry run is equivalent This is too likely to cause spurious bounces on CI; what we run may be dependent on what ran successfully before hand (e.g. RLS features with Clippy), which makes this not tenable. There's no good way to ignore specifically these problematic steps so we'll just ignore everything for the time being. We still test that a dry run worked though so largely this is the same from a ensure-that-tests-work perspective. Eventually we'll want to undo this commit, though, to make our tests more accurate. --- src/bootstrap/lib.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index c76b6180749c9..2eeb2691eaee4 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -416,22 +416,14 @@ impl Build { } if !self.config.dry_run { - let dry_graph = { + { self.config.dry_run = true; let builder = builder::Builder::new(&self); - builder.execute_cli() - }; + 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::>(), - act_graph.raw_nodes().iter().map(|i| &i.weight).collect::>()); - assert_eq!(dry_graph.raw_edges() - .iter().map(|i| (&dry_graph[i.source()], &dry_graph[i.target()], &i.weight)) - .collect::>(), - act_graph.raw_edges() - .iter().map(|i| (&act_graph[i.source()], &act_graph[i.target()], &i.weight)) - .collect::>()); + builder.execute_cli(); } else { let builder = builder::Builder::new(&self); let _ = builder.execute_cli();