|
| 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