diff --git a/Cargo.lock b/Cargo.lock index 17042358129..46c7d43ad2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1074,6 +1074,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.10" @@ -1566,7 +1575,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", - "itertools", + "itertools 0.10.5", "proc-macro2", "quote", "syn 1.0.109", @@ -1887,6 +1896,7 @@ dependencies = [ "fs_at", "git-testament", "home", + "itertools 0.12.0", "libc", "once_cell", "opener", diff --git a/Cargo.toml b/Cargo.toml index 2a84c608d22..7c6fec57fce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,7 @@ wait-timeout = "0.2" walkdir = { workspace = true, optional = true } xz2 = "0.1.3" zstd = "0.13" +itertools = "0.12.0" [target."cfg(windows)".dependencies] cc = "1" diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 8281e77ebe7..fd851d02237 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -10,6 +10,7 @@ use clap::{ Arg, ArgAction, ArgGroup, ArgMatches, Command, ValueEnum, }; use clap_complete::Shell; +use itertools::Itertools; use crate::{ cli::{ @@ -1334,11 +1335,22 @@ fn target_remove(cfg: &Cfg, m: &ArgMatches) -> Result { let distributable = DistributableToolchain::try_from(&toolchain)?; for target in m.get_many::("target").unwrap() { - let new_component = Component::new( - "rust-std".to_string(), - Some(TargetTriple::new(target)), - false, - ); + let target = TargetTriple::new(target); + let default_target = cfg.get_default_host_triple().ok(); + if default_target.as_ref() == Some(&target) { + warn!("after removing the default host target, proc-macros and build scripts might no longer build"); + } + let at_most_one_target = distributable.components().ok().and_then(|cs| { + // Every component target that is not `None` (wildcard). + let targets = cs + .iter() + .filter_map(|c| c.installed.then(|| c.component.target.clone()).flatten()); + targets.unique().at_most_one().ok() + }); + if at_most_one_target.is_some() { + warn!("after removing the last target, no build targets will be available"); + } + let new_component = Component::new("rust-std".to_string(), Some(target), false); distributable.remove_component(new_component)?; } diff --git a/tests/suite/cli_v2.rs b/tests/suite/cli_v2.rs index 563e6609fca..81ba41e75d0 100644 --- a/tests/suite/cli_v2.rs +++ b/tests/suite/cli_v2.rs @@ -952,9 +952,31 @@ fn remove_target_again() { #[test] fn remove_target_host() { setup(&|config| { - let trip = this_host_triple(); + let host = this_host_triple(); config.expect_ok(&["rustup", "default", "nightly"]); - config.expect_ok(&["rustup", "target", "remove", &trip]); + config.expect_ok(&["rustup", "target", "add", clitools::CROSS_ARCH1]); + config.expect_stderr_ok( + &["rustup", "target", "remove", &host], + "after removing the default host target, proc-macros and build scripts might no longer build", + ); + let path = format!("toolchains/nightly-{host}/lib/rustlib/{host}/lib/libstd.rlib"); + assert!(!config.rustupdir.has(path)); + let path = format!("toolchains/nightly-{host}/lib/rustlib/{host}/lib"); + assert!(!config.rustupdir.has(path)); + let path = format!("toolchains/nightly-{host}/lib/rustlib/{host}"); + assert!(!config.rustupdir.has(path)); + }); +} + +#[test] +fn remove_target_last() { + setup(&|config| { + let host = this_host_triple(); + config.expect_ok(&["rustup", "default", "nightly"]); + config.expect_stderr_ok( + &["rustup", "target", "remove", &host], + "after removing the last target, no build targets will be available", + ); }); }