From bf21fa281c61f1704dde06b0d2707b4c85158b5f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:09:41 +0000 Subject: [PATCH 1/6] fix(cargo): serialize rustup state across cargo install fallbacks Co-Authored-By: Claude Sonnet 5.5 Entire-Checkpoint: 01M4A1ZAJZFNWSD6YN4HJ86J19 --- src/backend/cargo.rs | 3 +++ src/plugins/core/mod.rs | 2 +- src/plugins/core/rust.rs | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/backend/cargo.rs b/src/backend/cargo.rs index 91a004c63e0..38b15b06a98 100644 --- a/src/backend/cargo.rs +++ b/src/backend/cargo.rs @@ -315,6 +315,9 @@ impl Backend for CargoBackend { ); } + // cargo may sync the toolchain through rustup, which can't run concurrently + let _rust_state_locks = + crate::plugins::core::rust::lock_rust_state_for_config(&config).await?; let mut cmd = CmdLineRunner::new( self.spawn_program(&ctx.config, Some(&ctx.ts), "cargo") .await, diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 4fe4286d7b9..138e4081a40 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -29,7 +29,7 @@ mod ruby_common; pub(crate) fn gemfile_watch_patterns(path: &std::path::Path) -> Vec { ruby_common::gemfile_watch_patterns(path) } -mod rust; +pub(crate) mod rust; mod swift; mod zig; diff --git a/src/plugins/core/rust.rs b/src/plugins/core/rust.rs index 55704ac891b..9cd09e142e6 100644 --- a/src/plugins/core/rust.rs +++ b/src/plugins/core/rust.rs @@ -973,6 +973,14 @@ fn rust_state_lock_identities(rustup_home: &Path, cargo_home: &Path) -> Vec, +) -> Result> { + lock_rust_state(&RustHomes::resolve(config).await?).await +} + async fn lock_rust_state(homes: &RustHomes) -> Result> { let identities = rust_state_lock_identities(&homes.rustup, &homes.cargo); tokio::task::spawn_blocking(move || { From 33cc2a49dbd3676e40c078f4afcff2fa2118899f Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:18:08 +0000 Subject: [PATCH 2/6] fix(cargo): key the rust state lock on install_env overrides Co-Authored-By: Claude Sonnet 5.5 Entire-Checkpoint: 01M4A2ESS3CAQ74RME1S69S9MX --- src/backend/cargo.rs | 3 ++- src/plugins/core/rust.rs | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/backend/cargo.rs b/src/backend/cargo.rs index 38b15b06a98..9547727a8d2 100644 --- a/src/backend/cargo.rs +++ b/src/backend/cargo.rs @@ -317,7 +317,8 @@ impl Backend for CargoBackend { // cargo may sync the toolchain through rustup, which can't run concurrently let _rust_state_locks = - crate::plugins::core::rust::lock_rust_state_for_config(&config).await?; + crate::plugins::core::rust::lock_rust_state_for_config(&config, &tv.install_env()) + .await?; let mut cmd = CmdLineRunner::new( self.spawn_program(&ctx.config, Some(&ctx.ts), "cargo") .await, diff --git a/src/plugins/core/rust.rs b/src/plugins/core/rust.rs index 9cd09e142e6..fc9110e8905 100644 --- a/src/plugins/core/rust.rs +++ b/src/plugins/core/rust.rs @@ -977,8 +977,24 @@ fn rust_state_lock_identities(rustup_home: &Path, cargo_home: &Path) -> Vec, + install_env: &IndexMap, ) -> Result> { - lock_rust_state(&RustHomes::resolve(config).await?).await + let mut config_env = config.env().await?.clone(); + for (key, value) in install_env { + match value.clone().into_string() { + Some(value) => config_env.insert(key.clone(), value), + None => config_env.shift_remove(key), + }; + } + let settings = Settings::get(); + let homes = RustHomes::from_sources( + &config_env, + settings.rust.cargo_home.clone(), + env::var_path("CARGO_HOME"), + settings.rust.rustup_home.clone(), + env::var_path("RUSTUP_HOME"), + ); + lock_rust_state(&homes).await } async fn lock_rust_state(homes: &RustHomes) -> Result> { From 0571eb017df4f9c209ad8cb92251add30c5327f2 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:28:19 +0000 Subject: [PATCH 3/6] fix(cargo): resolve rust lock homes from the toolset env Co-Authored-By: Claude Sonnet 5.5 Entire-Checkpoint: 01M4A31EB50FZC57J69A8J8QG9 --- src/backend/cargo.rs | 3 ++- src/plugins/core/rust.rs | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/backend/cargo.rs b/src/backend/cargo.rs index 9547727a8d2..2d20d06414a 100644 --- a/src/backend/cargo.rs +++ b/src/backend/cargo.rs @@ -315,9 +315,10 @@ impl Backend for CargoBackend { ); } + let toolset_env = ctx.ts.env_with_path_without_tools(&config).await?; // cargo may sync the toolchain through rustup, which can't run concurrently let _rust_state_locks = - crate::plugins::core::rust::lock_rust_state_for_config(&config, &tv.install_env()) + crate::plugins::core::rust::lock_rust_state_for_config(&toolset_env, &tv.install_env()) .await?; let mut cmd = CmdLineRunner::new( self.spawn_program(&ctx.config, Some(&ctx.ts), "cargo") diff --git a/src/plugins/core/rust.rs b/src/plugins/core/rust.rs index fc9110e8905..c56287b47c6 100644 --- a/src/plugins/core/rust.rs +++ b/src/plugins/core/rust.rs @@ -976,10 +976,13 @@ fn rust_state_lock_identities(rustup_home: &Path, cargo_home: &Path) -> Vec, + toolset_env: &BTreeMap, install_env: &IndexMap, ) -> Result> { - let mut config_env = config.env().await?.clone(); + let mut config_env: IndexMap = toolset_env + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); for (key, value) in install_env { match value.clone().into_string() { Some(value) => config_env.insert(key.clone(), value), From bae1e96e6c5b6aeee0f4df5558f43a5f8e94c070 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:46:21 +0000 Subject: [PATCH 4/6] fix(cargo): lock default homes when install_env unsets them Co-Authored-By: Claude Sonnet 5.5 Entire-Checkpoint: 01M4A42EGMGE7VCDTCV1ZDNR1P --- src/plugins/core/rust.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/plugins/core/rust.rs b/src/plugins/core/rust.rs index c56287b47c6..405d3674b48 100644 --- a/src/plugins/core/rust.rs +++ b/src/plugins/core/rust.rs @@ -983,19 +983,31 @@ pub(crate) async fn lock_rust_state_for_config( .iter() .map(|(k, v)| (k.clone(), v.clone())) .collect(); + let (mut cargo_removed, mut rustup_removed) = (false, false); for (key, value) in install_env { match value.clone().into_string() { - Some(value) => config_env.insert(key.clone(), value), - None => config_env.shift_remove(key), - }; + Some(value) => { + config_env.insert(key.clone(), value); + } + None => { + config_env.shift_remove(key); + // the child unsets the variable, so it uses the default home + cargo_removed |= key == "CARGO_HOME"; + rustup_removed |= key == "RUSTUP_HOME"; + } + } } let settings = Settings::get(); let homes = RustHomes::from_sources( &config_env, - settings.rust.cargo_home.clone(), - env::var_path("CARGO_HOME"), - settings.rust.rustup_home.clone(), - env::var_path("RUSTUP_HOME"), + settings.rust.cargo_home.clone().filter(|_| !cargo_removed), + env::var_path("CARGO_HOME").filter(|_| !cargo_removed), + settings + .rust + .rustup_home + .clone() + .filter(|_| !rustup_removed), + env::var_path("RUSTUP_HOME").filter(|_| !rustup_removed), ); lock_rust_state(&homes).await } From 771bdcf6fb31eaea802f82bebd8bd6f2e7860d16 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Oct 2026 02:52:27 +0000 Subject: [PATCH 5/6] fix(cargo): drop MISE_*_HOME fallback when install_env unsets the home Co-Authored-By: Claude Sonnet 5.5 Entire-Checkpoint: 01M4A4DM23MEXN0QAS21BVZJZK --- src/plugins/core/rust.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/core/rust.rs b/src/plugins/core/rust.rs index 405d3674b48..9c86c0d9341 100644 --- a/src/plugins/core/rust.rs +++ b/src/plugins/core/rust.rs @@ -992,8 +992,13 @@ pub(crate) async fn lock_rust_state_for_config( None => { config_env.shift_remove(key); // the child unsets the variable, so it uses the default home - cargo_removed |= key == "CARGO_HOME"; - rustup_removed |= key == "RUSTUP_HOME"; + if key == "CARGO_HOME" { + cargo_removed = true; + config_env.shift_remove("MISE_CARGO_HOME"); + } else if key == "RUSTUP_HOME" { + rustup_removed = true; + config_env.shift_remove("MISE_RUSTUP_HOME"); + } } } } From ee119aecbfd1bba01397fd6c982cb3b86b871d34 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Wed, 7 Oct 2026 03:04:09 +0000 Subject: [PATCH 6/6] fix(cargo): lock the homes cargo's child env actually resolves Co-Authored-By: Claude Sonnet 5.5 Entire-Checkpoint: 01M4A531625XTE3RGJBZDQ1F9E --- src/plugins/core/rust.rs | 42 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/src/plugins/core/rust.rs b/src/plugins/core/rust.rs index 9c86c0d9341..b19269e5e14 100644 --- a/src/plugins/core/rust.rs +++ b/src/plugins/core/rust.rs @@ -979,40 +979,22 @@ pub(crate) async fn lock_rust_state_for_config( toolset_env: &BTreeMap, install_env: &IndexMap, ) -> Result> { - let mut config_env: IndexMap = toolset_env - .iter() - .map(|(k, v)| (k.clone(), v.clone())) - .collect(); - let (mut cargo_removed, mut rustup_removed) = (false, false); + // Mirror the child's environment: it inherits the process env, then the toolset + // env and `install_env` override it. Cargo only reads CARGO_HOME/RUSTUP_HOME. + let mut effective: BTreeMap = env::vars_safe().collect(); + effective.extend(toolset_env.iter().map(|(k, v)| (k.clone(), v.clone()))); for (key, value) in install_env { match value.clone().into_string() { - Some(value) => { - config_env.insert(key.clone(), value); - } - None => { - config_env.shift_remove(key); - // the child unsets the variable, so it uses the default home - if key == "CARGO_HOME" { - cargo_removed = true; - config_env.shift_remove("MISE_CARGO_HOME"); - } else if key == "RUSTUP_HOME" { - rustup_removed = true; - config_env.shift_remove("MISE_RUSTUP_HOME"); - } - } - } + Some(value) => effective.insert(key.clone(), value), + None => effective.remove(key), + }; } - let settings = Settings::get(); let homes = RustHomes::from_sources( - &config_env, - settings.rust.cargo_home.clone().filter(|_| !cargo_removed), - env::var_path("CARGO_HOME").filter(|_| !cargo_removed), - settings - .rust - .rustup_home - .clone() - .filter(|_| !rustup_removed), - env::var_path("RUSTUP_HOME").filter(|_| !rustup_removed), + &IndexMap::new(), + None, + effective.get("CARGO_HOME").map(PathBuf::from), + None, + effective.get("RUSTUP_HOME").map(PathBuf::from), ); lock_rust_state(&homes).await }