about summary refs log tree commit diff
path: root/src/bootstrap
diff options
context:
space:
mode:
authorJoshua Nelson <jnelson@cloudflare.com>2022-02-06 21:24:47 -0600
committerMark Rousskov <mark.simulacrum@gmail.com>2022-03-07 17:06:11 -0500
commit984527f7bb49bd6e2d34e65d7629d2e0cdc464f6 (patch)
tree60d058182a3e006ee4f6670ec2eaa41286a25e9b /src/bootstrap
parent62b522ec3a8967501466bfe8889fe54667c4e4d1 (diff)
downloadrust-984527f7bb49bd6e2d34e65d7629d2e0cdc464f6.tar.gz
rust-984527f7bb49bd6e2d34e65d7629d2e0cdc464f6.zip
fix weird bug when `out` would get overridden by unit tests
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/bin/main.rs2
-rw-r--r--src/bootstrap/builder/tests.rs4
-rw-r--r--src/bootstrap/config.rs27
-rw-r--r--src/bootstrap/flags.rs2
-rw-r--r--src/bootstrap/test.rs2
5 files changed, 27 insertions, 10 deletions
diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs
index 9c41ab69c8b..6494e5b113b 100644
--- a/src/bootstrap/bin/main.rs
+++ b/src/bootstrap/bin/main.rs
@@ -11,7 +11,7 @@ use bootstrap::{Build, Config, Subcommand, VERSION};
 
 fn main() {
     let args = env::args().skip(1).collect::<Vec<_>>();
-    let config = Config::parse(&args);
+    let config = Config::parse(&args, false);
 
     // check_version warnings are not printed during setup
     let changelog_suggestion =
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index bc710344969..bd0be6da0b1 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -3,15 +3,15 @@ use crate::config::{Config, TargetSelection};
 use std::thread;
 
 fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
-    let mut config = Config::parse(&[cmd.to_owned()]);
+    let mut config = Config::parse(&[cmd.to_owned()], true);
     // don't save toolstates
     config.save_toolstates = None;
     config.dry_run = true;
     config.ninja_in_file = false;
-    // try to avoid spurious failures in dist where we create/delete each others file
     config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap());
     config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap());
     config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap());
+    // try to avoid spurious failures in dist where we create/delete each others file
     let dir = config
         .out
         .join("tmp-rustbuild-tests")
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index d7f474bfc80..fb387f94086 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -619,7 +619,7 @@ impl Config {
         config
     }
 
-    pub fn parse(args: &[String]) -> Config {
+    pub fn parse(args: &[String], unit_test: bool) -> Config {
         let flags = Flags::parse(&args);
 
         let mut config = Config::default_opts();
@@ -682,11 +682,26 @@ impl Config {
         let build = toml.build.unwrap_or_default();
 
         set(&mut config.out, build.build_dir.map(String::into));
-        t!(fs::create_dir_all(&config.out));
-        config.out = t!(
-            config.out.canonicalize(),
-            format!("failed to canonicalize {}", config.out.display())
-        );
+        // NOTE: Bootstrap spawns various commands with different working directories.
+        // To avoid writing to random places on the file system, `config.out` needs to be an absolute path.
+
+        // FIXME: using `canonicalize()` makes this a lot more complicated than it needs to be -
+        // if/when `std::path::absolute` lands, we should use that instead.
+
+        // HACK: in tests, we override the build directory manually.
+        // Avoid creating a directory we won't actually need.
+        // (The original motivation for this is that CI uses read-only directories.)
+        if !config.out.is_absolute() && !unit_test {
+            // canonicalize() gives a hard error if the directory doesn't exist
+            t!(
+                fs::create_dir_all(&config.out),
+                format!("failed to create build dir: {}", config.out.display())
+            );
+            config.out = t!(
+                config.out.canonicalize(),
+                format!("failed to canonicalize {}", config.out.display())
+            );
+        }
 
         if config.dry_run {
             let dir = config.out.join("tmp-dry-run");
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 1a4e6a96888..b12ba1e89e0 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -343,7 +343,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
 
             // All subcommands except `clean` can have an optional "Available paths" section
             if verbose {
-                let config = Config::parse(&["build".to_string()]);
+                let config = Config::parse(&["build".to_string()], false);
                 let build = Build::new(config);
 
                 let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index e4fcb287f12..1665affcf8f 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -2346,6 +2346,8 @@ impl Step for Bootstrap {
             .current_dir(builder.src.join("src/bootstrap"))
             .env("RUSTFLAGS", "-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
+            // HACK: bootstrap's tests want to know the output directory, but there's no way to set
+            // it except through config.toml. Set it through an env variable instead.
             .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out)
             .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo)
             .env("RUSTC_BOOTSTRAP", "1")