Skip to content

Commit 21add7c

Browse files
committed
Make component removal best-effort and order-independent
1 parent 9f7bd9c commit 21add7c

File tree

2 files changed

+106
-3
lines changed

2 files changed

+106
-3
lines changed

src/cli/rustup_mode.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,12 +1481,33 @@ async fn component_remove(
14811481
let distributable = DistributableToolchain::from_partial(toolchain, cfg).await?;
14821482
let target = get_target(target, &distributable);
14831483

1484+
let mut parsed_components = Vec::new();
1485+
let mut first_error = None;
1486+
14841487
for component in &components {
1485-
let new_component = Component::try_new(component, &distributable, target.as_ref())?;
1486-
distributable.remove_component(new_component).await?;
1488+
match Component::try_new(component, &distributable, target.as_ref()) {
1489+
Ok(new_component) => parsed_components.push(new_component),
1490+
Err(err) => {
1491+
if first_error.is_none() {
1492+
first_error = Some(err);
1493+
}
1494+
}
1495+
}
14871496
}
14881497

1489-
Ok(ExitCode::SUCCESS)
1498+
for component in parsed_components {
1499+
if let Err(err) = distributable.remove_component(component).await {
1500+
if first_error.is_none() {
1501+
first_error = Some(err);
1502+
}
1503+
}
1504+
}
1505+
1506+
if let Some(err) = first_error {
1507+
Err(err)
1508+
} else {
1509+
Ok(ExitCode::SUCCESS)
1510+
}
14901511
}
14911512

14921513
async fn toolchain_link(cfg: &Cfg<'_>, dest: &CustomToolchainName, src: &Path) -> Result<ExitCode> {

tests/suite/cli_rustup.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,6 +2136,88 @@ async fn add_remove_multiple_components() {
21362136
}
21372137
}
21382138

2139+
#[tokio::test]
2140+
async fn remove_multiple_components_is_best_effort_and_order_independent() {
2141+
let files = [
2142+
"lib/rustlib/src/rust-src/foo.rs".to_owned(),
2143+
format!("lib/rustlib/{}/analysis/libfoo.json", this_host_triple()),
2144+
];
2145+
2146+
// Case 1: invalid component first
2147+
let cx = CliTestContext::new(Scenario::SimpleV2).await;
2148+
cx.config
2149+
.expect(&["rustup", "default", "nightly"])
2150+
.await
2151+
.is_ok();
2152+
cx.config
2153+
.expect(&["rustup", "component", "add", "rust-src", "rust-analysis"])
2154+
.await
2155+
.is_ok();
2156+
2157+
for file in &files {
2158+
let path = format!("toolchains/nightly-{}/{}", this_host_triple(), file);
2159+
assert!(cx.config.rustupdir.has(&path));
2160+
}
2161+
2162+
cx.config
2163+
.expect(&[
2164+
"rustup",
2165+
"component",
2166+
"remove",
2167+
"bad-component",
2168+
"rust-src",
2169+
"rust-analysis",
2170+
])
2171+
.await
2172+
.is_err();
2173+
2174+
for file in &files {
2175+
let path = PathBuf::from(format!(
2176+
"toolchains/nightly-{}/{}",
2177+
this_host_triple(),
2178+
file
2179+
));
2180+
assert!(!cx.config.rustupdir.has(path.parent().unwrap()));
2181+
}
2182+
2183+
// Case 2: invalid component last
2184+
let cx = CliTestContext::new(Scenario::SimpleV2).await;
2185+
cx.config
2186+
.expect(&["rustup", "default", "nightly"])
2187+
.await
2188+
.is_ok();
2189+
cx.config
2190+
.expect(&["rustup", "component", "add", "rust-src", "rust-analysis"])
2191+
.await
2192+
.is_ok();
2193+
2194+
for file in &files {
2195+
let path = format!("toolchains/nightly-{}/{}", this_host_triple(), file);
2196+
assert!(cx.config.rustupdir.has(&path));
2197+
}
2198+
2199+
cx.config
2200+
.expect(&[
2201+
"rustup",
2202+
"component",
2203+
"remove",
2204+
"rust-src",
2205+
"rust-analysis",
2206+
"bad-component",
2207+
])
2208+
.await
2209+
.is_err();
2210+
2211+
for file in &files {
2212+
let path = PathBuf::from(format!(
2213+
"toolchains/nightly-{}/{}",
2214+
this_host_triple(),
2215+
file
2216+
));
2217+
assert!(!cx.config.rustupdir.has(path.parent().unwrap()));
2218+
}
2219+
}
2220+
21392221
#[tokio::test]
21402222
async fn file_override() {
21412223
let cx = CliTestContext::new(Scenario::SimpleV2).await;

0 commit comments

Comments
 (0)