From 360491cdb3afca0c40a69e6d68f7370c8b860728 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Tue, 12 Dec 2023 13:57:51 -0600 Subject: [PATCH] config: added rwlock around plugins map (#1143) * config: added rwlock around plugins map * Commit from GitHub Actions (rtx) * reduce write locking --------- Co-authored-by: rtx[bot] <123107610+rtx-vm@users.noreply.github.com> --- src/cli/asdf.rs | 4 +- src/cli/bin_paths.rs | 4 +- src/cli/current.rs | 14 +++---- src/cli/direnv/envrc.rs | 4 +- src/cli/direnv/exec.rs | 4 +- src/cli/doctor.rs | 10 ++--- src/cli/env.rs | 8 ++-- src/cli/exec.rs | 8 ++-- src/cli/external.rs | 21 ++++------ src/cli/hook_env.rs | 4 +- src/cli/install.rs | 16 ++++---- src/cli/latest.rs | 4 +- src/cli/link.rs | 2 +- src/cli/local.rs | 4 +- src/cli/ls.rs | 15 ++++--- src/cli/ls_remote.rs | 11 +++-- src/cli/outdated.rs | 6 +-- src/cli/plugins/install.rs | 22 +++++----- src/cli/plugins/ls.rs | 2 +- src/cli/plugins/ls_remote.rs | 6 +-- src/cli/plugins/uninstall.rs | 10 +++-- src/cli/plugins/update.rs | 7 +--- src/cli/prune.rs | 6 +-- src/cli/reshim.rs | 4 +- src/cli/shell.rs | 8 ++-- src/cli/sync/node.rs | 6 +-- src/cli/sync/python.rs | 2 +- src/cli/uninstall.rs | 6 +-- src/cli/upgrade.rs | 10 ++--- src/cli/use.rs | 8 ++-- src/cli/where.rs | 11 ++--- src/cli/which.rs | 6 +-- src/config/config_file/mod.rs | 9 +---- src/config/mod.rs | 69 +++++++++++++++++--------------- src/plugins/core/mod.rs | 4 +- src/plugins/external_plugin.rs | 2 +- src/plugins/mod.rs | 2 +- src/runtime_symlinks.rs | 2 +- src/shims.rs | 8 ++-- src/toolset/builder.rs | 2 +- src/toolset/mod.rs | 54 ++++++++++++------------- src/toolset/tool_version_list.rs | 19 +++------ 42 files changed, 192 insertions(+), 232 deletions(-) diff --git a/src/cli/asdf.rs b/src/cli/asdf.rs index feb073e3b..06ec017dd 100644 --- a/src/cli/asdf.rs +++ b/src/cli/asdf.rs @@ -36,7 +36,7 @@ impl Asdf { } } -fn list_versions(mut config: Config, out: &mut Output, args: &Vec) -> Result<()> { +fn list_versions(config: Config, out: &mut Output, args: &Vec) -> Result<()> { if args[2] == "all" { let mut new_args: Vec = vec!["rtx".into(), "ls-remote".into()]; if args.len() >= 3 { @@ -44,7 +44,7 @@ fn list_versions(mut config: Config, out: &mut Output, args: &Vec) -> Re } return Cli::new().run(config, &new_args, out); } - let ts = ToolsetBuilder::new().build(&mut config)?; + let ts = ToolsetBuilder::new().build(&config)?; let mut versions = ts.list_installed_versions(&config)?; let plugin = match args.len() { 3 => Some(&args[2]), diff --git a/src/cli/bin_paths.rs b/src/cli/bin_paths.rs index 0edcfc6b3..c05327f05 100644 --- a/src/cli/bin_paths.rs +++ b/src/cli/bin_paths.rs @@ -10,8 +10,8 @@ use crate::toolset::ToolsetBuilder; pub struct BinPaths {} impl BinPaths { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config)?; for p in ts.list_paths(&config) { rtxprintln!(out, "{}", p.display()); } diff --git a/src/cli/current.rs b/src/cli/current.rs index 27816afd8..92fc67b4c 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -20,18 +20,16 @@ pub struct Current { } impl Current { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config)?; match &self.plugin { Some(plugin_name) => { let plugin_name = unalias_plugin(plugin_name); - match config.plugins.get(plugin_name) { - Some(plugin) => self.one(&config, ts, out, plugin.clone()), - None => { - warn!("Plugin {} is not installed", plugin_name); - Ok(()) - } + let plugin = config.get_or_create_plugin(plugin_name); + if !plugin.is_installed() { + bail!("Plugin {} is not installed", plugin_name); } + self.one(&config, ts, out, plugin.clone()) } None => self.all(&config, ts, out), } diff --git a/src/cli/direnv/envrc.rs b/src/cli/direnv/envrc.rs index 1d3af25a9..651cbf5ae 100644 --- a/src/cli/direnv/envrc.rs +++ b/src/cli/direnv/envrc.rs @@ -17,8 +17,8 @@ use crate::{dirs, env}; pub struct Envrc {} impl Envrc { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config)?; let envrc_path = env::RTX_TMP_DIR .join("direnv") diff --git a/src/cli/direnv/exec.rs b/src/cli/direnv/exec.rs index eaf428b94..70d3e4cfe 100644 --- a/src/cli/direnv/exec.rs +++ b/src/cli/direnv/exec.rs @@ -20,8 +20,8 @@ struct DirenvWatches { } impl DirenvExec { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config)?; let mut cmd = env_cmd(); diff --git a/src/cli/doctor.rs b/src/cli/doctor.rs index f5904926b..a1bfbee51 100644 --- a/src/cli/doctor.rs +++ b/src/cli/doctor.rs @@ -22,8 +22,8 @@ use crate::{duration, env}; pub struct Doctor {} impl Doctor { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config)?; rtxprintln!(out, "{}", rtx_version()); rtxprintln!(out, "{}", build_info()); rtxprintln!(out, "{}", shell()); @@ -45,7 +45,7 @@ impl Doctor { ); let mut checks = Vec::new(); - for plugin in config.plugins.values() { + for plugin in config.list_plugins() { if !plugin.is_installed() { checks.push(format!("plugin {} is not installed", &plugin.name())); continue; @@ -123,8 +123,8 @@ fn render_config_files(config: &Config) -> String { fn render_plugins(config: &Config) -> String { let mut s = style("plugins:\n").bold().to_string(); let plugins = config - .plugins - .values() + .list_plugins() + .into_iter() .filter(|p| p.is_installed()) .collect::>(); let max_plugin_name_len = plugins.iter().map(|p| p.name().len()).max().unwrap_or(0) + 2; diff --git a/src/cli/env.rs b/src/cli/env.rs index 985cc7100..2d3f7b235 100644 --- a/src/cli/env.rs +++ b/src/cli/env.rs @@ -27,11 +27,9 @@ pub struct Env { } impl Env { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let mut ts = ToolsetBuilder::new() - .with_args(&self.tool) - .build(&mut config)?; - ts.install_arg_versions(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; + ts.install_arg_versions(&config)?; if self.json { self.output_json(config, out, ts) diff --git a/src/cli/exec.rs b/src/cli/exec.rs index 74b52c794..ba9cb3583 100644 --- a/src/cli/exec.rs +++ b/src/cli/exec.rs @@ -45,11 +45,9 @@ pub struct Exec { } impl Exec { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - let mut ts = ToolsetBuilder::new() - .with_args(&self.tool) - .build(&mut config)?; - ts.install_arg_versions(&mut config)?; + pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; + ts.install_arg_versions(&config)?; let (program, args) = parse_command(&env::SHELL, &self.command, &self.c); let env = ts.env_with_path(&config); diff --git a/src/cli/external.rs b/src/cli/external.rs index 9c4bc2cc1..51f507a27 100644 --- a/src/cli/external.rs +++ b/src/cli/external.rs @@ -1,26 +1,19 @@ use clap::{ArgMatches, Command}; use color_eyre::eyre::Result; -use itertools::Itertools; use rayon::prelude::*; use crate::config::Config; pub fn commands(config: &Config) -> Vec { config - .plugins - .values() - .collect_vec() + .list_plugins() .into_par_iter() - .flat_map(|p| match p.external_commands() { - Ok(commands) => commands, - Err(e) => { - warn!( - "failed to load external commands for plugin {}: {:#}", - p.name(), - e - ); + .flat_map(|p| { + p.external_commands().unwrap_or_else(|e| { + let p = p.name(); + warn!("failed to load external commands for plugin {p}: {e:#}"); vec![] - } + }) }) .collect() } @@ -36,7 +29,7 @@ pub fn execute( .find(|c| c.get_name() == plugin) { if let Some((subcommand, matches)) = args.subcommand() { - let plugin = config.plugins.get(&plugin.to_string()).unwrap(); + let plugin = config.get_or_create_plugin(plugin); let args: Vec = matches .get_raw("args") .unwrap_or_default() diff --git a/src/cli/hook_env.rs b/src/cli/hook_env.rs index 767dc37a9..817c8689e 100644 --- a/src/cli/hook_env.rs +++ b/src/cli/hook_env.rs @@ -32,8 +32,8 @@ pub struct HookEnv { } impl HookEnv { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config)?; let shell = get_shell(self.shell).expect("no shell provided, use `--shell=zsh`"); out.stdout.write(hook_env::clear_old_env(&*shell)); let mut env = ts.env(&config); diff --git a/src/cli/install.rs b/src/cli/install.rs index a8bfc989d..a6bb7ebc1 100644 --- a/src/cli/install.rs +++ b/src/cli/install.rs @@ -42,23 +42,23 @@ impl Install { Ok(()) } - fn install_runtimes(&self, mut config: Config, runtimes: &[ToolArg]) -> Result<()> { + fn install_runtimes(&self, config: Config, runtimes: &[ToolArg]) -> Result<()> { let mpr = MultiProgressReport::new(&config.settings); let mut ts = ToolsetBuilder::new() .with_latest_versions() - .build(&mut config)?; - let tool_versions = self.get_requested_tool_versions(&mut config, &ts, runtimes, &mpr)?; + .build(&config)?; + let tool_versions = self.get_requested_tool_versions(&config, &ts, runtimes, &mpr)?; if tool_versions.is_empty() { warn!("no runtimes to install"); warn!("specify a version with `rtx install @`"); return Ok(()); } - ts.install_versions(&mut config, tool_versions, &mpr, self.force) + ts.install_versions(&config, tool_versions, &mpr, self.force) } fn get_requested_tool_versions( &self, - config: &mut Config, + config: &Config, ts: &Toolset, runtimes: &[ToolArg], mpr: &MultiProgressReport, @@ -102,10 +102,10 @@ impl Install { Ok(tool_versions) } - fn install_missing_runtimes(&self, mut config: Config) -> Result<()> { + fn install_missing_runtimes(&self, config: Config) -> Result<()> { let mut ts = ToolsetBuilder::new() .with_latest_versions() - .build(&mut config)?; + .build(&config)?; let versions = ts .list_missing_versions(&config) .into_iter() @@ -116,7 +116,7 @@ impl Install { return Ok(()); } let mpr = MultiProgressReport::new(&config.settings); - ts.install_versions(&mut config, versions, &mpr, self.force)?; + ts.install_versions(&config, versions, &mpr, self.force)?; Ok(()) } } diff --git a/src/cli/latest.rs b/src/cli/latest.rs index 76a73336f..1f8d01ff7 100644 --- a/src/cli/latest.rs +++ b/src/cli/latest.rs @@ -26,7 +26,7 @@ pub struct Latest { } impl Latest { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let mut prefix = match self.tool.tvr { None => self.asdf_version, Some(ToolVersionRequest::Version(_, version)) => Some(version), @@ -37,7 +37,7 @@ impl Latest { }; let plugin = config.get_or_create_plugin(&self.tool.plugin); - plugin.ensure_installed(&mut config, None, false)?; + plugin.ensure_installed(&config, None, false)?; if let Some(v) = prefix { prefix = Some(config.resolve_alias(plugin.name(), &v)?); } diff --git a/src/cli/link.rs b/src/cli/link.rs index 6e5d9e64b..e95721196 100644 --- a/src/cli/link.rs +++ b/src/cli/link.rs @@ -33,7 +33,7 @@ pub struct Link { } impl Link { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { let version = match self.tool.tvr { Some(ref tvr) => tvr.version(), None => { diff --git a/src/cli/local.rs b/src/cli/local.rs index e57838cc6..89f2e3456 100644 --- a/src/cli/local.rs +++ b/src/cli/local.rs @@ -93,7 +93,7 @@ pub fn get_parent_path() -> Result { #[allow(clippy::too_many_arguments)] pub fn local( - mut config: Config, + config: Config, out: &mut Output, path: &Path, runtime: Vec, @@ -128,7 +128,7 @@ pub fn local( return Ok(()); } let pin = pin || (config.settings.asdf_compat && !fuzzy); - cf.add_runtimes(&mut config, &runtimes, pin)?; + cf.add_runtimes(&config, &runtimes, pin)?; let tools = runtimes.iter().map(|r| r.to_string()).join(" "); rtxprintln!( out, diff --git a/src/cli/ls.rs b/src/cli/ls.rs index 035691e46..e18a8d2d4 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -59,7 +59,7 @@ pub struct Ls { } impl Ls { - pub fn run(mut self, mut config: Config, out: &mut Output) -> Result<()> { + pub fn run(mut self, config: Config, out: &mut Output) -> Result<()> { self.plugin = self .plugin .clone() @@ -67,7 +67,7 @@ impl Ls { .map(|p| PluginName::from(unalias_plugin(&p))); self.verify_plugin(&config)?; - let mut runtimes = self.get_runtime_list(&mut config)?; + let mut runtimes = self.get_runtime_list(&config)?; if self.current || self.global { // TODO: global is a little weird: it will show global versions as the active ones even if // they're overridden locally @@ -94,8 +94,8 @@ impl Ls { fn verify_plugin(&self, config: &Config) -> Result<()> { match &self.plugin { Some(plugin_name) => { - let plugin = config.plugins.get(plugin_name); - if plugin.is_none() || !plugin.unwrap().is_installed() { + let plugin = config.get_or_create_plugin(plugin_name); + if !plugin.is_installed() { return Err(PluginNotInstalled(plugin_name.clone()))?; } } @@ -209,12 +209,11 @@ impl Ls { Ok(()) } - fn get_runtime_list(&self, config: &mut Config) -> Result> { + fn get_runtime_list(&self, config: &Config) -> Result> { let mut tsb = ToolsetBuilder::new().with_global_only(self.global); if let Some(plugin) = &self.plugin { tsb = tsb.with_tools(&[plugin]); - config.plugins.retain(|p, _| p == plugin); } let ts = tsb.build(config)?; let mut versions: HashMap<(String, String), (Arc, ToolVersion)> = ts @@ -233,6 +232,10 @@ impl Ls { let rvs: Vec = versions .into_iter() + .filter(|((plugin_name, _), _)| match &self.plugin { + Some(p) => p.eq(plugin_name), + None => true, + }) .sorted_by_cached_key(|((plugin_name, version), _)| { ( plugin_name.clone(), diff --git a/src/cli/ls_remote.rs b/src/cli/ls_remote.rs index ea2f90b41..f49afb8fa 100644 --- a/src/cli/ls_remote.rs +++ b/src/cli/ls_remote.rs @@ -33,8 +33,8 @@ pub struct LsRemote { } impl LsRemote { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - if let Some(plugin) = self.get_plugin(&mut config)? { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + if let Some(plugin) = self.get_plugin(&config)? { self.run_single(config, out, plugin) } else { self.run_all(config, out) @@ -68,9 +68,8 @@ impl LsRemote { fn run_all(self, config: Config, out: &mut Output) -> Result<()> { let versions = config - .plugins - .values() - .par_bridge() + .list_plugins() + .into_par_iter() .map(|p| { let versions = p.list_remote_versions(&config.settings)?; Ok((p, versions)) @@ -87,7 +86,7 @@ impl LsRemote { Ok(()) } - fn get_plugin(&self, config: &mut Config) -> Result>> { + fn get_plugin(&self, config: &Config) -> Result>> { match &self.plugin { Some(tool_arg) => { let plugin = config.get_or_create_plugin(&tool_arg.plugin); diff --git a/src/cli/outdated.rs b/src/cli/outdated.rs index ca78237cd..d2da32457 100644 --- a/src/cli/outdated.rs +++ b/src/cli/outdated.rs @@ -22,10 +22,8 @@ pub struct Outdated { } impl Outdated { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let mut ts = ToolsetBuilder::new() - .with_args(&self.tool) - .build(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let tool_set = self .tool .iter() diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index 1b79066e6..b3c72ba06 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -46,14 +46,14 @@ pub struct PluginsInstall { } impl PluginsInstall { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { let mpr = MultiProgressReport::new(&config.settings); if self.all { return self.install_all_missing_plugins(config, mpr); } let (name, git_url) = get_name_and_url(&self.new_plugin.clone().unwrap(), &self.git_url)?; if git_url.is_some() { - self.install_one(&mut config, name, git_url, &mpr)?; + self.install_one(&config, name, git_url, &mpr)?; } else { let mut plugins: Vec = vec![name]; if let Some(second) = self.git_url.clone() { @@ -66,13 +66,9 @@ impl PluginsInstall { Ok(()) } - fn install_all_missing_plugins( - &self, - mut config: Config, - mpr: MultiProgressReport, - ) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; - let missing_plugins = ts.list_missing_plugins(&mut config); + fn install_all_missing_plugins(&self, config: Config, mpr: MultiProgressReport) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config)?; + let missing_plugins = ts.list_missing_plugins(&config); if missing_plugins.is_empty() { warn!("all plugins already installed"); } @@ -82,12 +78,12 @@ impl PluginsInstall { fn install_many( &self, - mut config: Config, + config: Config, plugins: Vec, mpr: MultiProgressReport, ) -> Result<()> { for plugin in plugins { - self.install_one(&mut config, plugin, None, &mpr)?; + self.install_one(&config, plugin, None, &mpr)?; } Ok(()) // TODO: run in parallel @@ -97,7 +93,7 @@ impl PluginsInstall { // .install(|| -> Result<()> { // plugins // .into_par_iter() - // .map(|plugin| self.install_one(&mut config, plugin, None, &mpr)) + // .map(|plugin| self.install_one(&config, plugin, None, &mpr)) // .collect::>>()?; // Ok(()) // }) @@ -105,7 +101,7 @@ impl PluginsInstall { fn install_one( &self, - config: &mut Config, + config: &Config, name: PluginName, git_url: Option, mpr: &MultiProgressReport, diff --git a/src/cli/plugins/ls.rs b/src/cli/plugins/ls.rs index 20e57129e..bdba3e470 100644 --- a/src/cli/plugins/ls.rs +++ b/src/cli/plugins/ls.rs @@ -43,7 +43,7 @@ pub struct PluginsLs { impl PluginsLs { pub fn run(self, config: Config, out: &mut Output) -> Result<()> { - let mut tools = config.plugins.values().cloned().collect::>(); + let mut tools = config.list_plugins().into_iter().collect::>(); if self.all { for (plugin, url) in config.get_shorthands() { diff --git a/src/cli/plugins/ls_remote.rs b/src/cli/plugins/ls_remote.rs index 4ed8337c1..944ee6b1b 100644 --- a/src/cli/plugins/ls_remote.rs +++ b/src/cli/plugins/ls_remote.rs @@ -25,10 +25,10 @@ pub struct PluginsLsRemote { impl PluginsLsRemote { pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let installed_plugins = config - .plugins - .values() + .list_plugins() + .into_iter() .filter(|p| p.is_installed()) - .map(|p| p.name()) + .map(|p| p.name().to_string()) .collect::>(); let shorthands = config.get_shorthands().iter().sorted().collect_vec(); diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index 377a9be16..92bd26228 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -28,7 +28,11 @@ impl PluginsUninstall { let mpr = MultiProgressReport::new(&config.settings); let plugins = match self.all { - true => config.plugins.keys().cloned().collect(), + true => config + .list_plugins() + .into_iter() + .map(|p| p.name().to_string()) + .collect(), false => self.plugin.clone(), }; @@ -45,8 +49,8 @@ impl PluginsUninstall { plugin_name: &str, mpr: &MultiProgressReport, ) -> Result<()> { - match config.plugins.get(plugin_name) { - Some(plugin) if plugin.is_installed() => { + match config.get_or_create_plugin(plugin_name) { + plugin if plugin.is_installed() => { let mut pr = mpr.add(); plugin.decorate_progress_bar(&mut pr, None); plugin.uninstall(&pr)?; diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index fce3ea0d2..75d43eeae 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -1,5 +1,4 @@ -use color_eyre::eyre::{eyre, Result}; -use console::style; +use color_eyre::eyre::Result; use crate::config::Config; use crate::output::Output; @@ -31,9 +30,7 @@ impl Update { None => (p.as_str(), None), }; let p = unalias_plugin(p); - let plugin = config.plugins.get(p).ok_or_else(|| { - eyre!("plugin {} not found", style(p).cyan().for_stderr()) - })?; + let plugin = config.get_or_create_plugin(p); Ok((plugin.clone(), ref_)) }) .collect::>()?, diff --git a/src/cli/prune.rs b/src/cli/prune.rs index e86c89ccf..420cdf35e 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -30,8 +30,8 @@ pub struct Prune { } impl Prune { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; + pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config)?; let mut to_delete = ts .list_installed_versions(&config)? .into_iter() @@ -44,7 +44,7 @@ impl Prune { for cf in config.get_tracked_config_files()?.values() { let mut ts = cf.to_toolset().clone(); - ts.resolve(&mut config); + ts.resolve(&config); for (_, tv) in ts.list_current_versions(&config) { to_delete.remove(&tv.to_string()); } diff --git a/src/cli/reshim.rs b/src/cli/reshim.rs index efadbf474..bb565aa41 100644 --- a/src/cli/reshim.rs +++ b/src/cli/reshim.rs @@ -30,8 +30,8 @@ pub struct Reshim { } impl Reshim { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { - let ts = ToolsetBuilder::new().build(&mut config)?; + pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { + let ts = ToolsetBuilder::new().build(&config)?; shims::reshim(&config, &ts) } diff --git a/src/cli/shell.rs b/src/cli/shell.rs index 4d8412758..a1f1d4dc7 100644 --- a/src/cli/shell.rs +++ b/src/cli/shell.rs @@ -23,15 +23,13 @@ pub struct Shell { } impl Shell { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { if !config.is_activated() { err_inactive()?; } - let mut ts = ToolsetBuilder::new() - .with_args(&self.tool) - .build(&mut config)?; - ts.install_arg_versions(&mut config)?; + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; + ts.install_arg_versions(&config)?; let shell = get_shell(None).expect("no shell detected"); diff --git a/src/cli/sync/node.rs b/src/cli/sync/node.rs index 6609ac3e5..1c9279c8a 100644 --- a/src/cli/sync/node.rs +++ b/src/cli/sync/node.rs @@ -48,7 +48,7 @@ impl SyncNode { Ok(()) } - fn run_brew(self, mut config: Config, out: &mut Output) -> Result<()> { + fn run_brew(self, config: Config, out: &mut Output) -> Result<()> { let tool = config.get_or_create_plugin(&PluginName::from("node")); let brew_prefix = PathBuf::from(cmd!("brew", "--prefix").read()?).join("opt"); @@ -69,7 +69,7 @@ impl SyncNode { config.rebuild_shims_and_runtime_symlinks() } - fn run_nvm(self, mut config: Config, out: &mut Output) -> Result<()> { + fn run_nvm(self, config: Config, out: &mut Output) -> Result<()> { let tool = config.get_or_create_plugin(&PluginName::from("node")); let nvm_versions_path = NVM_DIR.join("versions").join("node"); @@ -87,7 +87,7 @@ impl SyncNode { config.rebuild_shims_and_runtime_symlinks() } - fn run_nodenv(self, mut config: Config, out: &mut Output) -> Result<()> { + fn run_nodenv(self, config: Config, out: &mut Output) -> Result<()> { let tool = config.get_or_create_plugin(&PluginName::from("node")); let nodenv_versions_path = NODENV_ROOT.join("versions"); diff --git a/src/cli/sync/python.rs b/src/cli/sync/python.rs index 2f2be6e90..ae28e2faf 100644 --- a/src/cli/sync/python.rs +++ b/src/cli/sync/python.rs @@ -20,7 +20,7 @@ pub struct SyncPython { } impl SyncPython { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let python = config.get_or_create_plugin(&PluginName::from("python")); let pyenv_versions_path = PYENV_ROOT.join("versions"); diff --git a/src/cli/uninstall.rs b/src/cli/uninstall.rs index 9f1ebc33e..b20ab9a04 100644 --- a/src/cli/uninstall.rs +++ b/src/cli/uninstall.rs @@ -26,7 +26,7 @@ pub struct Uninstall { } impl Uninstall { - pub fn run(self, mut config: Config, _out: &mut Output) -> Result<()> { + pub fn run(self, config: Config, _out: &mut Output) -> Result<()> { let runtimes = ToolArg::double_tool_condition(&self.tool); let mut tool_versions = vec![]; @@ -59,7 +59,7 @@ impl Uninstall { vec![tvr.resolve(&config, tool.clone(), Default::default(), false)?] } None => { - let ts = ToolsetBuilder::new().build(&mut config)?; + let ts = ToolsetBuilder::new().build(&config)?; match ts.versions.get(&a.plugin) { Some(tvl) => tvl.versions.clone(), None => bail!( @@ -96,7 +96,7 @@ impl Uninstall { pr.finish_with_message("uninstalled"); } - let ts = ToolsetBuilder::new().build(&mut config)?; + let ts = ToolsetBuilder::new().build(&config)?; shims::reshim(&config, &ts).wrap_err("failed to reshim")?; runtime_symlinks::rebuild(&config)?; diff --git a/src/cli/upgrade.rs b/src/cli/upgrade.rs index 9ba3aa6bb..aaa49eed4 100644 --- a/src/cli/upgrade.rs +++ b/src/cli/upgrade.rs @@ -30,10 +30,8 @@ pub struct Upgrade { } impl Upgrade { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let mut ts = ToolsetBuilder::new() - .with_args(&self.tool) - .build(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; let tool_set = self .tool .iter() @@ -45,13 +43,13 @@ impl Upgrade { if outdated.is_empty() { info!("All tools are up to date"); } else { - self.upgrade(&mut config, outdated, out)?; + self.upgrade(&config, outdated, out)?; } Ok(()) } - fn upgrade(&self, config: &mut Config, outdated: OutputVec, out: &mut Output) -> Result<()> { + fn upgrade(&self, config: &Config, outdated: OutputVec, out: &mut Output) -> Result<()> { let mpr = MultiProgressReport::new(&config.settings); let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(config)?; diff --git a/src/cli/use.rs b/src/cli/use.rs index b63deac43..96fee8f1b 100644 --- a/src/cli/use.rs +++ b/src/cli/use.rs @@ -64,11 +64,9 @@ pub struct Use { } impl Use { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let mut ts = ToolsetBuilder::new() - .with_args(&self.tool) - .build(&mut config)?; - ts.install_arg_versions(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let mut ts = ToolsetBuilder::new().with_args(&self.tool).build(&config)?; + ts.install_arg_versions(&config)?; ts.versions .retain(|_, tvl| self.tool.iter().any(|t| t.plugin == tvl.plugin_name)); diff --git a/src/cli/where.rs b/src/cli/where.rs index 8b0368fe5..ee81e5e7b 100644 --- a/src/cli/where.rs +++ b/src/cli/where.rs @@ -2,7 +2,7 @@ use color_eyre::eyre::Result; use crate::cli::args::tool::{ToolArg, ToolArgParser}; use crate::config::Config; -use crate::errors::Error::{PluginNotInstalled, VersionNotInstalled}; +use crate::errors::Error::VersionNotInstalled; use crate::output::Output; use crate::toolset::ToolsetBuilder; @@ -28,14 +28,14 @@ pub struct Where { } impl Where { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { let runtime = match self.tool.tvr { None => match self.asdf_version { Some(version) => self.tool.with_version(&version), None => { let ts = ToolsetBuilder::new() .with_args(&[self.tool.clone()]) - .build(&mut config)?; + .build(&config)?; let v = ts .versions .get(&self.tool.plugin) @@ -47,10 +47,7 @@ impl Where { _ => self.tool, }; - let plugin = match config.plugins.get(&runtime.plugin) { - Some(plugin) => plugin, - None => Err(PluginNotInstalled(runtime.plugin.clone()))?, - }; + let plugin = config.get_or_create_plugin(&runtime.plugin); match runtime .tvr diff --git a/src/cli/which.rs b/src/cli/which.rs index 034d6826f..f580a3501 100644 --- a/src/cli/which.rs +++ b/src/cli/which.rs @@ -28,8 +28,8 @@ pub struct Which { } impl Which { - pub fn run(self, mut config: Config, out: &mut Output) -> Result<()> { - let ts = self.get_toolset(&mut config)?; + pub fn run(self, config: Config, out: &mut Output) -> Result<()> { + let ts = self.get_toolset(&config)?; match ts.which(&config, &self.bin_name) { Some((p, tv)) => { @@ -46,7 +46,7 @@ impl Which { None => Err(eyre!("{} not found", self.bin_name)), } } - fn get_toolset(&self, config: &mut Config) -> Result { + fn get_toolset(&self, config: &Config) -> Result { let mut tsb = ToolsetBuilder::new(); if let Some(tool) = &self.tool { tsb = tsb.with_args(&[tool.clone()]); diff --git a/src/config/config_file/mod.rs b/src/config/config_file/mod.rs index f94053b3a..97c7a08b4 100644 --- a/src/config/config_file/mod.rs +++ b/src/config/config_file/mod.rs @@ -65,12 +65,7 @@ pub trait ConfigFile: Debug + Display + Send + Sync { } impl dyn ConfigFile { - pub fn add_runtimes( - &mut self, - config: &mut Config, - runtimes: &[ToolArg], - pin: bool, - ) -> Result<()> { + pub fn add_runtimes(&mut self, config: &Config, runtimes: &[ToolArg], pin: bool) -> Result<()> { // TODO: this has become a complete mess and could probably be greatly simplified let mpr = MultiProgressReport::new(&config.settings); let mut ts = self.to_toolset().to_owned(); @@ -104,7 +99,7 @@ impl dyn ConfigFile { .into_iter() .map(|tvr| { if pin { - let plugin = config.plugins.get(&plugin).unwrap(); + let plugin = config.get_or_create_plugin(&plugin); let tv = tvr.resolve( config, plugin.clone(), diff --git a/src/config/mod.rs b/src/config/mod.rs index 8e72966d9..720e058fb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use std::fmt::{Display, Formatter}; use std::path::PathBuf; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use std::thread; use eyre::Context; @@ -37,7 +37,6 @@ pub struct Config { pub settings: Settings, pub global_config: RtxToml, pub config_files: ConfigMap, - pub plugins: PluginMap, pub env: BTreeMap, pub env_sources: HashMap, pub path_dirs: Vec, @@ -45,6 +44,7 @@ pub struct Config { pub all_aliases: OnceCell, pub should_exit_early: bool, pub project_root: Option, + plugins: RwLock, shorthands: OnceCell>, repo_urls: HashMap, } @@ -114,7 +114,7 @@ impl Config { config_files, settings, global_config, - plugins, + plugins: RwLock::new(plugins), should_exit_early, repo_urls, }; @@ -151,7 +151,7 @@ impl Config { return Ok(alias.clone()); } } - if let Some(plugin) = self.plugins.get(plugin_name) { + if let Some(plugin) = self.plugins.read().unwrap().get(plugin_name) { if let Some(alias) = plugin.get_aliases(&self.settings)?.get(v) { return Ok(alias.clone()); } @@ -159,36 +159,40 @@ impl Config { Ok(v.to_string()) } - pub fn external_plugins(&self) -> Vec<(&PluginName, Arc)> { - self.plugins - .iter() - .filter(|(_, tool)| matches!(tool.get_type(), PluginType::External)) - .map(|(name, tool)| (name, tool.clone())) + pub fn external_plugins(&self) -> Vec<(String, Arc)> { + self.list_plugins() + .into_iter() + .filter(|tool| matches!(tool.get_type(), PluginType::External)) + .map(|tool| (tool.name().to_string(), tool.clone())) .collect() } - pub fn get_or_create_plugin(&mut self, plugin_name: &PluginName) -> Arc { + pub fn get_or_create_plugin(&self, plugin_name: &str) -> Arc { + if let Some(plugin) = self.plugins.read().unwrap().get(plugin_name) { + return plugin.clone(); + } + let plugin = ExternalPlugin::newa(plugin_name.to_string()); self.plugins - .entry(plugin_name.clone()) - .or_insert_with(|| ExternalPlugin::newa(plugin_name.clone())) - .clone() + .write() + .unwrap() + .insert(plugin_name.to_string(), plugin.clone()); + plugin + } + pub fn list_plugins(&self) -> Vec> { + self.plugins.read().unwrap().values().cloned().collect() } fn load_all_aliases(&self) -> AliasMap { let mut aliases: AliasMap = self.aliases.clone(); let plugin_aliases: Vec<_> = self - .plugins - .values() - .par_bridge() + .list_plugins() + .into_par_iter() .map(|plugin| { - let aliases = match plugin.get_aliases(&self.settings) { - Ok(aliases) => aliases, - Err(err) => { - eprintln!("Error: {err}"); - BTreeMap::new() - } - }; - (plugin.name(), aliases) + let aliases = plugin.get_aliases(&self.settings).unwrap_or_else(|err| { + warn!("get_aliases: {err}"); + BTreeMap::new() + }); + (plugin.name().to_string(), aliases) }) .collect(); for (plugin, plugin_aliases) in plugin_aliases { @@ -231,7 +235,7 @@ impl Config { Ok(config_files) } - pub fn rebuild_shims_and_runtime_symlinks(&mut self) -> Result<()> { + pub fn rebuild_shims_and_runtime_symlinks(&self) -> Result<()> { let ts = crate::toolset::ToolsetBuilder::new().build(self)?; crate::shims::reshim(self, &ts)?; crate::runtime_symlinks::rebuild(self)?; @@ -351,10 +355,9 @@ fn load_config_filenames( } fn get_global_rtx_toml() -> PathBuf { - match env::RTX_CONFIG_FILE.clone() { - Some(global) => global, - None => dirs::CONFIG.join("config.toml"), - } + env::RTX_CONFIG_FILE + .clone() + .unwrap_or_else(|| dirs::CONFIG.join("config.toml")) } pub fn global_config_files() -> Vec { @@ -481,10 +484,10 @@ fn track_config_files(config_filenames: &[PathBuf]) -> thread::JoinHandle<()> { impl Display for Config { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let plugins = self - .plugins - .iter() - .filter(|(_, t)| matches!(t.get_type(), PluginType::External)) - .map(|(p, _)| p.to_string()) + .list_plugins() + .into_iter() + .filter(|t| matches!(t.get_type(), PluginType::External)) + .map(|t| t.name().to_string()) .collect::>(); let config_files = self .config_files diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index ad9ccf09b..8d7a79d4b 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -19,7 +19,7 @@ use crate::plugins::core::java::JavaPlugin; use crate::plugins::core::node::NodePlugin; use crate::plugins::core::node_build::NodeBuildPlugin; use crate::plugins::core::ruby::RubyPlugin; -use crate::plugins::{Plugin, PluginName, HTTP}; +use crate::plugins::{Plugin, HTTP}; use crate::timeout::run_with_timeout; use crate::toolset::ToolVersion; use crate::{dirs, env}; @@ -33,7 +33,7 @@ mod node_build; mod python; mod ruby; -pub type PluginMap = BTreeMap>; +pub type PluginMap = BTreeMap>; pub static CORE_PLUGINS: Lazy = Lazy::new(|| { let plugins: Vec> = vec![ diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index a50998d9a..5440cc8ea 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -470,7 +470,7 @@ impl Plugin for ExternalPlugin { fn ensure_installed( &self, - config: &mut Config, + config: &Config, mpr: Option<&MultiProgressReport>, force: bool, ) -> Result<()> { diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 4873e4e37..2b5c3cb4c 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -153,7 +153,7 @@ pub trait Plugin: Debug + Send + Sync { } fn ensure_installed( &self, - _config: &mut Config, + _config: &Config, _mpr: Option<&MultiProgressReport>, _force: bool, ) -> Result<()> { diff --git a/src/runtime_symlinks.rs b/src/runtime_symlinks.rs index af4957dd1..19e108c12 100644 --- a/src/runtime_symlinks.rs +++ b/src/runtime_symlinks.rs @@ -14,7 +14,7 @@ use crate::plugins::Plugin; use crate::{dirs, file}; pub fn rebuild(config: &Config) -> Result<()> { - for plugin in config.plugins.values() { + for plugin in config.list_plugins() { let symlinks = list_symlinks(config, plugin.clone())?; let installs_dir = dirs::INSTALLS.join(plugin.name()); for (from, to) in symlinks { diff --git a/src/shims.rs b/src/shims.rs index a94888997..fc2f644dd 100644 --- a/src/shims.rs +++ b/src/shims.rs @@ -23,13 +23,13 @@ use crate::{dirs, file}; // executes as if it was a shim if the command is not "rtx", e.g.: "node" #[allow(dead_code)] -pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Result { +pub fn handle_shim(config: Config, args: &[String], out: &mut Output) -> Result { let (_, bin_name) = args[0].rsplit_once('/').unwrap_or(("", &args[0])); if bin_name == "rtx" { return Ok(config); } let mut args: Vec = args.iter().map(OsString::from).collect(); - args[0] = which_shim(&mut config, bin_name)?.into(); + args[0] = which_shim(&config, bin_name)?.into(); let exec = Exec { tool: vec![], c: None, @@ -40,7 +40,7 @@ pub fn handle_shim(mut config: Config, args: &[String], out: &mut Output) -> Res exit(0); } -fn which_shim(config: &mut Config, bin_name: &str) -> Result { +fn which_shim(config: &Config, bin_name: &str) -> Result { let shim = dirs::SHIMS.join(bin_name); if shim.exists() { let ts = ToolsetBuilder::new().build(config)?; @@ -117,7 +117,7 @@ pub fn reshim(config: &Config, ts: &Toolset) -> Result<()> { let symlink_path = dirs::SHIMS.join(shim); remove_all(&symlink_path)?; } - for plugin in config.plugins.values() { + for plugin in config.list_plugins() { match dirs::PLUGINS.join(plugin.name()).join("shims").read_dir() { Ok(files) => { for bin in files { diff --git a/src/toolset/builder.rs b/src/toolset/builder.rs index fb129cc1e..d42f33bbb 100644 --- a/src/toolset/builder.rs +++ b/src/toolset/builder.rs @@ -41,7 +41,7 @@ impl ToolsetBuilder { self } - pub fn build(self, config: &mut Config) -> Result { + pub fn build(self, config: &Config) -> Result { let mut toolset = Toolset { latest_versions: self.latest_versions, disable_tools: config.settings.disable_tools.clone(), diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index a31f4daea..f982ae9f3 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -75,7 +75,7 @@ impl Toolset { self.versions = versions; self.source = other.source.clone(); } - pub fn resolve(&mut self, config: &mut Config) { + pub fn resolve(&mut self, config: &Config) { self.list_missing_plugins(config); self.versions .iter_mut() @@ -83,7 +83,7 @@ impl Toolset { .par_iter_mut() .for_each(|(_, v)| v.resolve(config, self.latest_versions)); } - pub fn install_arg_versions(&mut self, config: &mut Config) -> Result<()> { + pub fn install_arg_versions(&mut self, config: &Config) -> Result<()> { let mpr = MultiProgressReport::new(&config.settings); let versions = self .list_missing_versions(config) @@ -94,7 +94,7 @@ impl Toolset { self.install_versions(config, versions, &mpr, false) } - pub fn list_missing_plugins(&self, config: &mut Config) -> Vec { + pub fn list_missing_plugins(&self, config: &Config) -> Vec { self.versions .keys() .map(|p| config.get_or_create_plugin(p)) @@ -105,7 +105,7 @@ impl Toolset { pub fn install_versions( &mut self, - config: &mut Config, + config: &Config, versions: Vec, mpr: &MultiProgressReport, force: bool, @@ -130,7 +130,6 @@ impl Toolset { (0..config.settings.jobs) .map(|_| { let queue = queue.clone(); - let config = &*config; let ts = &*self; s.spawn(move || { let next_job = || queue.lock().unwrap().pop(); @@ -167,7 +166,7 @@ impl Toolset { self.versions .iter() .map(|(p, tvl)| { - let p = config.plugins.get(p).unwrap(); + let p = config.get_or_create_plugin(p); (p, tvl) }) .flat_map(|(p, tvl)| { @@ -188,23 +187,24 @@ impl Toolset { .map(|(p, tv)| ((p.name().into(), tv.version.clone()), (p.clone(), tv))) .collect(); let versions = config - .plugins - .values() - .collect_vec() + .list_plugins() .into_par_iter() .map(|p| { let versions = p.list_installed_versions()?; - Ok(versions.into_iter().map(|v| { - match current_versions.get(&(p.name().into(), v.clone())) { - Some((p, tv)) => (p.clone(), tv.clone()), - None => { - let tv = ToolVersionRequest::new(p.name().into(), &v) - .resolve(config, p.clone(), Default::default(), false) - .unwrap(); - (p.clone(), tv) - } - } - })) + Ok(versions + .into_iter() + .map( + |v| match current_versions.get(&(p.name().into(), v.clone())) { + Some((p, tv)) => (p.clone(), tv.clone()), + None => { + let tv = ToolVersionRequest::new(p.name().into(), &v) + .resolve(config, p.clone(), Default::default(), false) + .unwrap(); + (p.clone(), tv) + } + }, + ) + .collect_vec()) }) .collect::>>()? .into_iter() @@ -219,10 +219,7 @@ impl Toolset { ) -> Vec<(Arc, &Vec)> { self.versions .iter() - .map(|(p, v)| { - let p = config.plugins.get(p).unwrap(); - (p.clone(), &v.versions) - }) + .map(|(p, v)| (config.get_or_create_plugin(p), &v.versions)) .collect() } pub fn list_current_versions(&self, config: &Config) -> Vec<(Arc, ToolVersion)> { @@ -313,12 +310,11 @@ impl Toolset { pub fn list_paths(&self, config: &Config) -> Vec { self.list_current_installed_versions(config) .into_par_iter() - .flat_map(|(p, tv)| match p.list_bin_paths(config, self, &tv) { - Ok(paths) => paths, - Err(e) => { - warn!("Error listing bin paths for {}: {:#}", tv, e); + .flat_map(|(p, tv)| { + p.list_bin_paths(config, self, &tv).unwrap_or_else(|e| { + warn!("Error listing bin paths for {tv}: {e:#}"); Vec::new() - } + }) }) .collect() } diff --git a/src/toolset/tool_version_list.rs b/src/toolset/tool_version_list.rs index 88894056d..6fdf34007 100644 --- a/src/toolset/tool_version_list.rs +++ b/src/toolset/tool_version_list.rs @@ -22,13 +22,7 @@ impl ToolVersionList { } pub fn resolve(&mut self, config: &Config, latest_versions: bool) { self.versions.clear(); - let plugin = match config.plugins.get(&self.plugin_name) { - Some(p) => p, - _ => { - debug!("Plugin {} is not installed", self.plugin_name); - return; - } - }; + let plugin = config.get_or_create_plugin(&self.plugin_name); for (tvr, opts) in &mut self.requests { match tvr.resolve(config, plugin.clone(), opts.clone(), latest_versions) { Ok(v) => self.versions.push(v), @@ -40,17 +34,15 @@ impl ToolVersionList { #[cfg(test)] mod tests { - use crate::plugins::ExternalPlugin; use crate::{dirs, env, file}; use super::*; #[test] fn test_tool_version_list() { - let mut config = Config::default(); + let config = Config::default(); let plugin_name = "tiny".to_string(); - let plugin = ExternalPlugin::newa(plugin_name.clone()); - config.plugins.insert(plugin_name.clone(), plugin); + config.get_or_create_plugin(&plugin_name); let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); tvl.requests.push(( ToolVersionRequest::new(plugin_name, "latest"), @@ -64,10 +56,9 @@ mod tests { fn test_tool_version_list_failure() { env::set_var("RTX_FAILURE", "1"); file::remove_all(dirs::CACHE.join("dummy")).unwrap(); - let mut config = Config::default(); + let config = Config::default(); let plugin_name = "dummy".to_string(); - let plugin = ExternalPlugin::newa(plugin_name.clone()); - config.plugins.insert(plugin_name.clone(), plugin); + config.get_or_create_plugin(&plugin_name); let mut tvl = ToolVersionList::new(plugin_name.clone(), ToolSource::Argument); tvl.requests.push(( ToolVersionRequest::new(plugin_name, "latest"),