diff --git a/src/dist/dist.rs b/src/dist/dist.rs index c892e724a8..699d7a5a0e 100644 --- a/src/dist/dist.rs +++ b/src/dist/dist.rs @@ -498,6 +498,7 @@ pub(crate) struct Manifest<'a>(temp::File<'a>, String); #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] pub enum Profile { + Empty, Minimal, Default, Complete, @@ -508,6 +509,7 @@ impl FromStr for Profile { fn from_str(name: &str) -> Result { match name { + "empty" | "e" => Ok(Self::Empty), "minimal" | "m" => Ok(Self::Minimal), "default" | "d" | "" => Ok(Self::Default), "complete" | "c" => Ok(Self::Complete), @@ -522,7 +524,7 @@ impl FromStr for Profile { impl Profile { pub(crate) fn names() -> &'static [&'static str] { - &["minimal", "default", "complete"] + &["empty", "minimal", "default", "complete"] } pub(crate) fn default_name() -> &'static str { @@ -579,6 +581,7 @@ impl fmt::Display for ToolchainDesc { impl fmt::Display for Profile { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { + Self::Empty => write!(f, "empty"), Self::Minimal => write!(f, "minimal"), Self::Default => write!(f, "default"), Self::Complete => write!(f, "complete"), @@ -813,8 +816,8 @@ fn try_update_from_dist_<'a>( )); let profile_components = match profile { + Some(Profile::Empty) | None => Vec::new(), Some(profile) => m.get_profile_components(profile, &toolchain.target)?, - None => Vec::new(), }; let mut all_components: HashSet = profile_components.into_iter().collect(); @@ -854,6 +857,7 @@ fn try_update_from_dist_<'a>( let changes = Changes { explicit_add_components, remove_components: Vec::new(), + permit_empty: profile == Some(Profile::Empty), }; *fetched = m.date.clone(); diff --git a/src/dist/manifestation.rs b/src/dist/manifestation.rs index 7fb33df053..0623610e47 100644 --- a/src/dist/manifestation.rs +++ b/src/dist/manifestation.rs @@ -35,6 +35,7 @@ pub struct Manifestation { pub struct Changes { pub explicit_add_components: Vec, pub remove_components: Vec, + pub permit_empty: bool, } impl Changes { @@ -118,7 +119,7 @@ impl Manifestation { let mut update = Update::build_update(self, new_manifest, &changes, &config, notify_handler)?; - if update.nothing_changes() { + if update.nothing_changes() && !changes.permit_empty { return Ok(UpdateStatus::Unchanged); } diff --git a/src/toolchain.rs b/src/toolchain.rs index 951dbf31f3..c1e23740f9 100644 --- a/src/toolchain.rs +++ b/src/toolchain.rs @@ -580,6 +580,7 @@ impl<'a> DistributableToolchain<'a> { let changes = Changes { explicit_add_components: vec![component], remove_components: vec![], + permit_empty: false, }; desc.manifestation.update( @@ -855,6 +856,7 @@ impl<'a> DistributableToolchain<'a> { let changes = Changes { explicit_add_components: vec![], remove_components: vec![component], + permit_empty: false, }; desc.manifestation.update( diff --git a/tests/cli-inst-interactive.rs b/tests/cli-inst-interactive.rs index b75203f49a..a6caf26012 100644 --- a/tests/cli-inst-interactive.rs +++ b/tests/cli-inst-interactive.rs @@ -215,7 +215,7 @@ fn installer_shows_default_profile() { println!("-- stderr --\n {}", out.stderr); assert!(out.stdout.contains( r" -Profile (which tools and data to install)? (minimal/default/complete) [default] +Profile (which tools and data to install)? (empty/minimal/default/complete) [default] " )); }); @@ -234,7 +234,7 @@ fn installer_shows_default_profile_when_set_in_args() { println!("-- stderr --\n {}", out.stderr); assert!(out.stdout.contains( r" -Profile (which tools and data to install)? (minimal/default/complete) [minimal] +Profile (which tools and data to install)? (empty/minimal/default/complete) [minimal] " )); }); diff --git a/tests/cli-v2.rs b/tests/cli-v2.rs index 85060a6e4a..6ff8898b7f 100644 --- a/tests/cli-v2.rs +++ b/tests/cli-v2.rs @@ -1536,3 +1536,135 @@ fn regression_2601() { ); }); } + +#[test] +fn empty_profile_can_be_installed() { + setup(&|config| { + expect_ok( + config, + &[ + "rustup", + "toolchain", + "install", + "--profile", + "empty", + "nightly", + ], + ); + // In theory there should be no installed components, but the toolchain should be present + expect_ok_ex( + config, + &[ + "rustup", + "component", + "list", + "--installed", + "--toolchain", + "nightly", + ], + "", + "", + ); + }); +} + +#[test] +fn empty_profile_can_be_uninstalled() { + setup(&|config| { + expect_ok( + config, + &[ + "rustup", + "toolchain", + "install", + "--profile", + "empty", + "nightly", + ], + ); + // In theory there should be no installed components, but the toolchain should be present + expect_ok(config, &["rustup", "toolchain", "uninstall", "nightly"]); + }); +} + +#[test] +fn empty_profile_can_manipulate_components() { + setup(&|config| { + expect_ok( + config, + &[ + "rustup", + "toolchain", + "install", + "--profile", + "empty", + "nightly", + ], + ); + // In theory there should be no installed components, but the toolchain should be present + expect_ok_ex( + config, + &[ + "rustup", + "component", + "list", + "--installed", + "--toolchain", + "nightly", + ], + "", + "", + ); + // Install rust-src and check for it + expect_ok( + config, + &[ + "rustup", + "component", + "add", + "--toolchain", + "nightly", + "rust-src", + ], + ); + expect_ok_ex( + config, + &[ + "rustup", + "component", + "list", + "--installed", + "--toolchain", + "nightly", + ], + "rust-src\n", + "", + ); + + // Remove rust-src and check we're back to blank + expect_ok( + config, + &[ + "rustup", + "component", + "remove", + "--toolchain", + "nightly", + "rust-src", + ], + ); + expect_ok_ex( + config, + &[ + "rustup", + "component", + "list", + "--installed", + "--toolchain", + "nightly", + ], + "", + "", + ); + }); +} diff --git a/tests/dist.rs b/tests/dist.rs index 4636de73b3..470d8efaf4 100644 --- a/tests/dist.rs +++ b/tests/dist.rs @@ -459,6 +459,7 @@ fn update_from_dist( let changes = Changes { explicit_add_components: add_components, remove_components: remove.to_owned(), + permit_empty: false, }; manifestation.update(