| 
 | 1 | +use crate::TargetSelection;  | 
1 | 2 | use crate::{t, VERSION};  | 
2 | 3 | use std::fmt::Write as _;  | 
3 | 4 | use std::path::{Path, PathBuf};  | 
@@ -107,6 +108,17 @@ pub fn setup(src_path: &Path, profile: Profile) {  | 
107 | 108 |     let include_path = profile.include_path(src_path);  | 
108 | 109 |     println!("`x.py` will now use the configuration at {}", include_path.display());  | 
109 | 110 | 
 
  | 
 | 111 | +    let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));  | 
 | 112 | +    let stage_path = ["build", build.rustc_target_arg(), "stage1"].join("/");  | 
 | 113 | + | 
 | 114 | +    println!();  | 
 | 115 | + | 
 | 116 | +    if !rustup_installed() && profile != Profile::User {  | 
 | 117 | +        println!("`rustup` is not installed; cannot link `stage1` toolchain");  | 
 | 118 | +    } else if stage_dir_exists(&stage_path[..]) {  | 
 | 119 | +        attempt_toolchain_link(&stage_path[..]);  | 
 | 120 | +    }  | 
 | 121 | + | 
110 | 122 |     let suggestions = match profile {  | 
111 | 123 |         Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],  | 
112 | 124 |         Profile::Tools => &[  | 
@@ -139,6 +151,74 @@ pub fn setup(src_path: &Path, profile: Profile) {  | 
139 | 151 |     }  | 
140 | 152 | }  | 
141 | 153 | 
 
  | 
 | 154 | +fn rustup_installed() -> bool {  | 
 | 155 | +    Command::new("rustup")  | 
 | 156 | +        .arg("--version")  | 
 | 157 | +        .stdout(std::process::Stdio::null())  | 
 | 158 | +        .output()  | 
 | 159 | +        .map_or(false, |output| output.status.success())  | 
 | 160 | +}  | 
 | 161 | + | 
 | 162 | +fn stage_dir_exists(stage_path: &str) -> bool {  | 
 | 163 | +    match fs::create_dir(&stage_path[..]) {  | 
 | 164 | +        Ok(_) => true,  | 
 | 165 | +        Err(_) => Path::new(&stage_path[..]).exists(),  | 
 | 166 | +    }  | 
 | 167 | +}  | 
 | 168 | + | 
 | 169 | +fn attempt_toolchain_link(stage_path: &str) {  | 
 | 170 | +    if toolchain_is_linked() {  | 
 | 171 | +        return;  | 
 | 172 | +    }  | 
 | 173 | + | 
 | 174 | +    if try_link_toolchain(&stage_path[..]) {  | 
 | 175 | +        println!(  | 
 | 176 | +            "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"  | 
 | 177 | +        );  | 
 | 178 | +    } else {  | 
 | 179 | +        println!("`rustup` failed to link stage 1 build to `stage1` toolchain");  | 
 | 180 | +        println!(  | 
 | 181 | +            "To manually link stage 1 build to `stage1` toolchain, run:\n  | 
 | 182 | +            `rustup toolchain link stage1 {}`",  | 
 | 183 | +            &stage_path[..]  | 
 | 184 | +        );  | 
 | 185 | +    }  | 
 | 186 | +}  | 
 | 187 | + | 
 | 188 | +fn toolchain_is_linked() -> bool {  | 
 | 189 | +    match Command::new("rustup")  | 
 | 190 | +        .args(&["toolchain", "list"])  | 
 | 191 | +        .stdout(std::process::Stdio::piped())  | 
 | 192 | +        .output()  | 
 | 193 | +    {  | 
 | 194 | +        Ok(toolchain_list) => {  | 
 | 195 | +            if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") {  | 
 | 196 | +                return false;  | 
 | 197 | +            }  | 
 | 198 | +            // The toolchain has already been linked.  | 
 | 199 | +            println!(  | 
 | 200 | +                "`stage1` toolchain already linked; not attempting to link `stage1` toolchain"  | 
 | 201 | +            );  | 
 | 202 | +        }  | 
 | 203 | +        Err(_) => {  | 
 | 204 | +            // In this case, we don't know if the `stage1` toolchain has been linked;  | 
 | 205 | +            // but `rustup` failed, so let's not go any further.  | 
 | 206 | +            println!(  | 
 | 207 | +                "`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain"  | 
 | 208 | +            );  | 
 | 209 | +        }  | 
 | 210 | +    }  | 
 | 211 | +    true  | 
 | 212 | +}  | 
 | 213 | + | 
 | 214 | +fn try_link_toolchain(stage_path: &str) -> bool {  | 
 | 215 | +    Command::new("rustup")  | 
 | 216 | +        .stdout(std::process::Stdio::null())  | 
 | 217 | +        .args(&["toolchain", "link", "stage1", &stage_path[..]])  | 
 | 218 | +        .output()  | 
 | 219 | +        .map_or(false, |output| output.status.success())  | 
 | 220 | +}  | 
 | 221 | + | 
142 | 222 | // Used to get the path for `Subcommand::Setup`  | 
143 | 223 | pub fn interactive_path() -> io::Result<Profile> {  | 
144 | 224 |     fn abbrev_all() -> impl Iterator<Item = ((String, String), Profile)> {  | 
 | 
0 commit comments