about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTimothy Maloney <tmaloney@pdx.edu>2021-09-23 17:24:58 -0700
committerTimothy Maloney <tmaloney@pdx.edu>2021-09-26 21:26:30 -0700
commitadbb608678c618efdc823e3c7a60a0331b9c0156 (patch)
tree851ff2f5b813f62391daa3e0b12eba5c57ab396d
parent0132f8258ae0fbc4f2b461b28d510222d22aa979 (diff)
downloadrust-adbb608678c618efdc823e3c7a60a0331b9c0156.tar.gz
rust-adbb608678c618efdc823e3c7a60a0331b9c0156.zip
Link stage1 build to toolchain automatically
Fixed types

Add checks for rustup and if toolchain is linked

Fortified rustup/directory checks; made other suggested changes

Added check for output status

Remove output of rustup from console

Made suggested change

Deleted confusing comment

Fixed compiler error; removed extra declaration

Refactored to smaller components; made suggested changes

Automate toolchain linking for stage 1 builds
-rw-r--r--src/bootstrap/setup.rs80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs
index a5829dfa9d8..5bc0a505bf6 100644
--- a/src/bootstrap/setup.rs
+++ b/src/bootstrap/setup.rs
@@ -1,3 +1,4 @@
+use crate::TargetSelection;
 use crate::{t, VERSION};
 use std::fmt::Write as _;
 use std::path::{Path, PathBuf};
@@ -107,6 +108,17 @@ pub fn setup(src_path: &Path, profile: Profile) {
     let include_path = profile.include_path(src_path);
     println!("`x.py` will now use the configuration at {}", include_path.display());
 
+    let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
+    let stage_path = ["build", build.rustc_target_arg(), "stage1"].join("/");
+
+    println!();
+
+    if !rustup_installed() && profile != Profile::User {
+        println!("`rustup` is not installed; cannot link `stage1` toolchain");
+    } else if stage_dir_exists(&stage_path[..]) {
+        attempt_toolchain_link(&stage_path[..]);
+    }
+
     let suggestions = match profile {
         Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
         Profile::Tools => &[
@@ -139,6 +151,74 @@ pub fn setup(src_path: &Path, profile: Profile) {
     }
 }
 
+fn rustup_installed() -> bool {
+    Command::new("rustup")
+        .arg("--version")
+        .stdout(std::process::Stdio::null())
+        .output()
+        .map_or(false, |output| output.status.success())
+}
+
+fn stage_dir_exists(stage_path: &str) -> bool {
+    match fs::create_dir(&stage_path[..]) {
+        Ok(_) => true,
+        Err(_) => Path::new(&stage_path[..]).exists(),
+    }
+}
+
+fn attempt_toolchain_link(stage_path: &str) {
+    if toolchain_is_linked() {
+        return;
+    }
+
+    if try_link_toolchain(&stage_path[..]) {
+        println!(
+            "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
+        );
+    } else {
+        println!("`rustup` failed to link stage 1 build to `stage1` toolchain");
+        println!(
+            "To manually link stage 1 build to `stage1` toolchain, run:\n
+            `rustup toolchain link stage1 {}`",
+            &stage_path[..]
+        );
+    }
+}
+
+fn toolchain_is_linked() -> bool {
+    match Command::new("rustup")
+        .args(&["toolchain", "list"])
+        .stdout(std::process::Stdio::piped())
+        .output()
+    {
+        Ok(toolchain_list) => {
+            if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") {
+                return false;
+            }
+            // The toolchain has already been linked.
+            println!(
+                "`stage1` toolchain already linked; not attempting to link `stage1` toolchain"
+            );
+        }
+        Err(_) => {
+            // In this case, we don't know if the `stage1` toolchain has been linked;
+            // but `rustup` failed, so let's not go any further.
+            println!(
+                "`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain"
+            );
+        }
+    }
+    true
+}
+
+fn try_link_toolchain(stage_path: &str) -> bool {
+    Command::new("rustup")
+        .stdout(std::process::Stdio::null())
+        .args(&["toolchain", "link", "stage1", &stage_path[..]])
+        .output()
+        .map_or(false, |output| output.status.success())
+}
+
 // Used to get the path for `Subcommand::Setup`
 pub fn interactive_path() -> io::Result<Profile> {
     fn abbrev_all() -> impl Iterator<Item = ((String, String), Profile)> {