diff --git a/e2e/cli/test_hook_not_found_auto_install b/e2e/cli/test_hook_not_found_auto_install new file mode 100755 index 0000000000..0505ed7e36 --- /dev/null +++ b/e2e/cli/test_hook_not_found_auto_install @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +# Test that not_found_auto_install works when a tool is already configured but not installed +# Reproduces https://github.com/jdx/mise/discussions/6482#discussioncomment-14552091 + +# Test 1: hook-not-found auto-install +# Set up: Install tiny@3.1.0 globally +mise use -g tiny@3.1.0 +assert "mise current tiny" "3.1.0" + +# Create a project that requires a different version (tiny@3.0.0) +cat >mise.toml <mise.toml <, bin_name: &str) -> Result return Ok(bin); } } - if Settings::get().not_found_auto_install && console::user_attended() { + if Settings::get().not_found_auto_install { for tv in ts .install_missing_bin(config, bin_name) .await? diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index 6c7e84169a..8c25d2f2fd 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -860,12 +860,43 @@ impl Toolset { config: &mut Arc, bin_name: &str, ) -> Result>> { + // Strategy: Find backends that could provide this bin by checking: + // 1. Any currently installed versions that provide the bin + // 2. Any requested backends with installed versions (even if not current) let mut plugins = IndexSet::new(); + + // First check currently active installed versions for (p, tv) in self.list_current_installed_versions(config) { if let Ok(Some(_bin)) = p.which(config, &tv, bin_name).await { plugins.insert(p); } } + + // Also check backends that are requested but not currently active + // This handles the case where a user has tool@v1 globally and tool@v2 locally (not installed) + // When looking for a bin provided by the tool, we check if any installed version provides it + let all_installed = self.list_installed_versions(config).await?; + for (backend, _versions) in self.list_versions_by_plugin() { + // Skip if we already found this backend + if plugins.contains(&backend) { + continue; + } + + // Check if this backend has ANY installed version that provides the bin + let backend_versions: Vec<_> = all_installed + .iter() + .filter(|(p, _)| p.ba() == backend.ba()) + .collect(); + + for (_, tv) in backend_versions { + if let Ok(Some(_bin)) = backend.which(config, tv, bin_name).await { + plugins.insert(backend.clone()); + break; + } + } + } + + // Install missing versions for backends that provide this bin for plugin in plugins { let versions = self .list_missing_versions(config)