diff --git a/README.md b/README.md index 4f4308ada2..e907caef91 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ v20.0.0 - [Core Plugins](#core-plugins) - [FAQs](#faqs) - [I don't want to put a `.tool-versions` file into my project since git shows it as an untracked file.](#i-dont-want-to-put-a-tool-versions-file-into-my-project-since-git-shows-it-as-an-untracked-file) + - [What is the difference between "nodejs" and "node" (or "golang" and "go")?](#what-is-the-difference-between-nodejs-and-node-or-golang-and-go) - [What does `rtx activate` do?](#what-does-rtx-activate-do) - [`rtx activate` doesn't work in `~/.profile`, `~/.bash_profile`, `~/.zprofile`](#rtx-activate-doesnt-work-in-profile-bash_profile-zprofile) - [rtx is failing or not working right](#rtx-is-failing-or-not-working-right) @@ -625,7 +626,7 @@ in rtx and nvm. Here are some of the supported legacy version files: |------------| -------------------------------------------------- | | crystal | `.crystal-version` | | elixir | `.exenv-version` | -| golang | `.go-version`, `go.mod` | +| go | `.go-version`, `go.mod` | | java | `.java-version` | | node | `.nvmrc`, `.node-version` | | python | `.python-version` | @@ -659,7 +660,7 @@ ruby 3 # can be fuzzy version shellcheck latest # also supports "latest" jq 1.6 erlang ref:master # compile from vcs ref -golang prefix:1.19 # uses the latest 1.19.x version—needed in case "1.19" is an exact match +go prefix:1.19 # uses the latest 1.19.x version—needed in case "1.19" is an exact match shfmt path:./shfmt # use a custom runtime node lts # use lts version of node (not supported by all plugins) @@ -770,7 +771,7 @@ information. Set to "0" to disable legacy version file parsing. -#### `RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS=nodejs,python` +#### `RTX_LEGACY_VERSION_FILE_DISABLE_TOOLS=node,python` Disable legacy version file parsing for specific tools. Separate with `,`. @@ -850,7 +851,7 @@ node = "https://github.com/my-org/rtx-node.git" Disables the shorthand aliases for installing plugins. You will have to specify full urls when installing plugins, e.g.: `rtx plugin install node https://github.com/asdf-vm/asdf-node.git` -#### `RTX_DISABLE_TOOLS=python,nodejs` +#### `RTX_DISABLE_TOOLS=python,node` Disables the specified tools. Separate with `,`. Generally used for core plugins but works with all. @@ -1122,6 +1123,23 @@ You can make git ignore these files in 3 different ways: - Adding `.tool-versions` to project's `.git/info/exclude`. This file is local to your project so there is no need to commit it. - Adding `.tool-versions` to global gitignore (`core.excludesFile`). This will cause git to ignore `.tool-versions` files in all projects. You can explicitly add one to a project if needed with `git add --force .tool-versions`. +### What is the difference between "nodejs" and "node" (or "golang" and "go")? + +These are aliased. For example, `rtx use nodejs@14.0` is the same as `rtx install node@14.0`. This +means it is not possible to have these be different plugins. + +This is for convenience so you don't need to remember which one is the "official" name. However if +something with the aliasing is acting up, submit a ticket or just stick to using "node" and "go". +Under the hood, when rtx reads a config file or takes CLI input it will swap out "nodejs" and +"golang". + +While this change is rolling out, there is some migration code that will move installs/plugins from +the "nodejs" and "golang" directories to the new names. If this runs for you you'll see a message +but it should not run again unless there is some kind of problem. In this case, it's probably +easiest to just run `rm -rf ~/.local/share/rtx/installs/{golang,nodejs} ~/.local/share/rtx/plugins/{golang,nodejs}`. + +Once most users have migrated over this migration code will be removed. + ### What does `rtx activate` do? It registers a shell hook to run `rtx hook-env` every time the shell prompt is *displayed*. diff --git a/e2e/gopath/test_gopath b/e2e/gopath/test_gopath index 70394bfb2d..c2e0162bf5 100755 --- a/e2e/gopath/test_gopath +++ b/e2e/gopath/test_gopath @@ -13,8 +13,8 @@ assert_gopath() { } rtx i golang@1.18.10 golang@1.19.5 && _rtx_hook -assert_gopath "$RTX_DATA_DIR/installs/golang/1.19.5/packages" +assert_gopath "$RTX_DATA_DIR/installs/go/1.19.5/packages" cd 18 && _rtx_hook -assert_gopath "$RTX_DATA_DIR/installs/golang/1.18.10/packages" +assert_gopath "$RTX_DATA_DIR/installs/go/1.18.10/packages" cd .. && _rtx_hook -assert_gopath "$RTX_DATA_DIR/installs/golang/1.19.5/packages" +assert_gopath "$RTX_DATA_DIR/installs/go/1.19.5/packages" diff --git a/e2e/test_nodejs b/e2e/test_nodejs index 4330608256..5e1c83b6e3 100755 --- a/e2e/test_nodejs +++ b/e2e/test_nodejs @@ -15,12 +15,14 @@ assert_contains "rtx node node-build --version" "node-build " rtx plugin i nodejs rtx use nodejs@20.1.0 assert "rtx x -- node --version" "v20.1.0" -assert_contains "rtx nodejs nodebuild --version" "node-build " -rtx plugin uninstall nodejs +assert_contains "rtx node nodebuild --version" "node-build " +rtx use --rm node # RTX_LEGACY_VERSION_FILE env var +rtx ls RTX_LEGACY_VERSION_FILE=1 assert_contains "rtx current node" "20.0.0" RTX_LEGACY_VERSION_FILE=0 assert_not_contains "rtx current node" "20.0.0" +rtx plugin uninstall nodejs # disable nodejs plugin RTX_DISABLE_TOOLS=node assert_not_contains "rtx plugins --core" "node" diff --git a/src/cli/args/tool.rs b/src/cli/args/tool.rs index 46884f732f..2c8f32439b 100644 --- a/src/cli/args/tool.rs +++ b/src/cli/args/tool.rs @@ -5,7 +5,7 @@ use clap::{Arg, Command, Error}; use color_eyre::eyre::Result; use regex::Regex; -use crate::plugins::PluginName; +use crate::plugins::{unalias_plugin, PluginName}; use crate::toolset::ToolVersionRequest; #[derive(Debug, Clone, Eq, PartialEq)] @@ -17,12 +17,15 @@ pub struct ToolArg { impl ToolArg { pub fn parse(input: &str) -> Self { match input.split_once('@') { - Some((plugin, version)) => Self { - plugin: plugin.to_string(), - tvr: Some(ToolVersionRequest::new(plugin.to_string(), version)), - }, + Some((plugin, version)) => { + let plugin = unalias_plugin(plugin).to_string(); + Self { + plugin: plugin.clone(), + tvr: Some(ToolVersionRequest::new(plugin, version)), + } + } None => Self { - plugin: input.into(), + plugin: unalias_plugin(input).into(), tvr: None, }, } diff --git a/src/cli/current.rs b/src/cli/current.rs index 2a9ab7e30e..e40e6563a0 100644 --- a/src/cli/current.rs +++ b/src/cli/current.rs @@ -4,6 +4,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::plugins::unalias_plugin; use crate::tool::Tool; use crate::toolset::{Toolset, ToolsetBuilder}; @@ -24,13 +25,16 @@ impl Command for Current { fn run(self, mut config: Config, out: &mut Output) -> Result<()> { let ts = ToolsetBuilder::new().build(&mut config)?; match &self.plugin { - Some(plugin_name) => match config.tools.get(plugin_name) { - Some(plugin) => self.one(&config, ts, out, plugin), - None => { - warn!("Plugin {} is not installed", plugin_name); - Ok(()) + Some(plugin_name) => { + let plugin_name = unalias_plugin(plugin_name); + match config.tools.get(plugin_name) { + Some(plugin) => self.one(&config, ts, out, plugin), + None => { + warn!("Plugin {} is not installed", plugin_name); + Ok(()) + } } - }, + } None => self.all(&config, ts, out), } } diff --git a/src/cli/ls.rs b/src/cli/ls.rs index fa9c5e19e4..1a75ad6fb6 100644 --- a/src/cli/ls.rs +++ b/src/cli/ls.rs @@ -15,7 +15,7 @@ use crate::cli::command::Command; use crate::config::Config; use crate::errors::Error::PluginNotInstalled; use crate::output::Output; -use crate::plugins::PluginName; +use crate::plugins::{unalias_plugin, PluginName}; use crate::tool::Tool; use crate::toolset::{ToolSource, ToolVersion, ToolsetBuilder}; @@ -58,7 +58,11 @@ pub struct Ls { impl Command for Ls { fn run(mut self, mut config: Config, out: &mut Output) -> Result<()> { - self.plugin = self.plugin.clone().or(self.plugin_arg.clone()); + self.plugin = self + .plugin + .clone() + .or(self.plugin_arg.clone()) + .map(|p| PluginName::from(unalias_plugin(&p))); self.verify_plugin(&config)?; let mut runtimes = self.get_runtime_list(&mut config)?; diff --git a/src/cli/plugins/install.rs b/src/cli/plugins/install.rs index e93ea851a5..df68f464e4 100644 --- a/src/cli/plugins/install.rs +++ b/src/cli/plugins/install.rs @@ -6,7 +6,7 @@ use url::Url; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::{ExternalPlugin, Plugin, PluginName}; +use crate::plugins::{unalias_plugin, ExternalPlugin, Plugin, PluginName}; use crate::tool::Tool; use crate::toolset::ToolsetBuilder; use crate::ui::multi_progress_report::MultiProgressReport; @@ -126,6 +126,7 @@ impl PluginsInstall { } fn get_name_and_url(name: &str, git_url: &Option) -> Result<(String, Option)> { + let name = unalias_plugin(name); Ok(match git_url { Some(url) => match url.contains("://") { true => (name.to_string(), Some(url.clone())), @@ -145,7 +146,7 @@ fn get_name_from_url(url: &str) -> Result { let name = last.strip_prefix("asdf-").unwrap_or(last); let name = name.strip_prefix("rtx-").unwrap_or(name); let name = name.strip_suffix(".git").unwrap_or(name); - return Ok(name.to_string()); + return Ok(unalias_plugin(name).to_string()); } } Err(eyre!("could not infer plugin name from url: {}", url)) diff --git a/src/cli/plugins/link.rs b/src/cli/plugins/link.rs index 1d298f73a6..e13d503226 100644 --- a/src/cli/plugins/link.rs +++ b/src/cli/plugins/link.rs @@ -11,6 +11,7 @@ use crate::config::Config; use crate::dirs; use crate::file::{make_symlink, remove_all}; use crate::output::Output; +use crate::plugins::unalias_plugin; /// Symlinks a plugin into rtx /// @@ -43,8 +44,9 @@ impl Command for PluginsLink { (name, path) } }; + let name = unalias_plugin(&name); let path = path.absolutize()?; - let symlink = dirs::PLUGINS.join(&name); + let symlink = dirs::PLUGINS.join(name); if symlink.exists() { if self.force { remove_all(&symlink)?; @@ -65,7 +67,7 @@ fn get_name_from_path(path: &Path) -> String { let name = path.file_name().unwrap().to_str().unwrap(); let name = name.strip_prefix("asdf-").unwrap_or(name); let name = name.strip_prefix("rtx-").unwrap_or(name); - name.to_string() + unalias_plugin(name).to_string() } static AFTER_LONG_HELP: &str = color_print::cstr!( diff --git a/src/cli/plugins/uninstall.rs b/src/cli/plugins/uninstall.rs index e080f53be3..c82adc5cf2 100644 --- a/src/cli/plugins/uninstall.rs +++ b/src/cli/plugins/uninstall.rs @@ -4,6 +4,7 @@ use console::style; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; +use crate::plugins::unalias_plugin; use crate::ui::multi_progress_report::MultiProgressReport; /// Removes a plugin @@ -20,6 +21,7 @@ impl Command for PluginsUninstall { let mpr = MultiProgressReport::new(config.show_progress_bars()); for plugin_name in &self.plugin { + let plugin_name = unalias_plugin(plugin_name); self.uninstall_one(&config, plugin_name, &mpr)?; } Ok(()) @@ -30,7 +32,7 @@ impl PluginsUninstall { fn uninstall_one( &self, config: &Config, - plugin_name: &String, + plugin_name: &str, mpr: &MultiProgressReport, ) -> Result<()> { match config.tools.get(plugin_name) { diff --git a/src/cli/plugins/update.rs b/src/cli/plugins/update.rs index 342a61e8d3..e8ac9f112e 100644 --- a/src/cli/plugins/update.rs +++ b/src/cli/plugins/update.rs @@ -4,7 +4,7 @@ use console::style; use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; -use crate::plugins::PluginName; +use crate::plugins::{unalias_plugin, PluginName}; /// Updates a plugin to the latest version /// @@ -31,6 +31,7 @@ impl Command for Update { Some((p, ref_)) => (p, Some(ref_.to_string())), None => (p.as_str(), None), }; + let p = unalias_plugin(p); let plugin = config.tools.get(p).ok_or_else(|| { eyre!("plugin {} not found", style(p).cyan().for_stderr()) })?; diff --git a/src/cli/prune.rs b/src/cli/prune.rs index 7fa115d710..cdef2a64dc 100644 --- a/src/cli/prune.rs +++ b/src/cli/prune.rs @@ -1,8 +1,9 @@ -use color_eyre::eyre::Result; -use console::style; use std::collections::BTreeMap; use std::sync::Arc; +use color_eyre::eyre::Result; +use console::style; + use crate::cli::command::Command; use crate::config::Config; use crate::output::Output; diff --git a/src/config/config_file/rtx_toml.rs b/src/config/config_file/rtx_toml.rs index 2efd03771f..468d7e74b1 100644 --- a/src/config/config_file/rtx_toml.rs +++ b/src/config/config_file/rtx_toml.rs @@ -15,7 +15,7 @@ use crate::config::settings::SettingsBuilder; use crate::config::{config_file, AliasMap, MissingRuntimeBehavior}; use crate::errors::Error::UntrustedConfig; use crate::file::create_dir_all; -use crate::plugins::PluginName; +use crate::plugins::{unalias_plugin, PluginName}; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ ToolSource, ToolVersionList, ToolVersionOptions, ToolVersionRequest, Toolset, @@ -234,8 +234,9 @@ impl RtxToml { Some(table) => { for (plugin, v) in table.iter() { let k = format!("{}.{}", key, plugin); - let tvl = self.parse_tool_version_list(&k, v, &plugin.to_string())?; - toolset.versions.insert(plugin.into(), tvl); + let plugin_name = unalias_plugin(plugin).to_string(); + let tvl = self.parse_tool_version_list(&k, v, &plugin_name)?; + toolset.versions.insert(plugin_name, tvl); } Ok(toolset) } diff --git a/src/config/config_file/tool_versions.rs b/src/config/config_file/tool_versions.rs index 76ccaf6df3..186cbf4095 100644 --- a/src/config/config_file/tool_versions.rs +++ b/src/config/config_file/tool_versions.rs @@ -14,7 +14,7 @@ use tera::Context; use crate::config::config_file::{ConfigFile, ConfigFileType}; use crate::config::settings::SettingsBuilder; use crate::file::display_path; -use crate::plugins::PluginName; +use crate::plugins::{unalias_plugin, PluginName}; use crate::tera::{get_tera, BASE_CONTEXT}; use crate::toolset::{ToolSource, ToolVersionRequest, Toolset}; @@ -98,7 +98,7 @@ impl ToolVersions { // handle invalid trailing colons in `.tool-versions` files // note that this method will cause the colons to be removed // permanently if saving the file again, but I think that's fine - let plugin = plugin.trim_end_matches(':'); + let plugin = unalias_plugin(plugin.trim_end_matches(':')); let tvp = ToolVersionPlugin { versions: parts.map(|v| v.to_string()).collect(), diff --git a/src/main.rs b/src/main.rs index 65340f6607..344951321f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,6 +39,7 @@ mod hook_env; mod http; mod lock_file; mod logger; +mod migrate; mod plugins; mod runtime_symlinks; mod shell; @@ -73,6 +74,9 @@ fn run(args: &Vec) -> Result<()> { // show version before loading config in case of error cli::version::print_version_if_requested(&env::ARGS, out); + if let Err(err) = migrate::run() { + warn!("Error migrating: {}", err); + } let config = Config::load()?; let config = shims::handle_shim(config, args, out)?; diff --git a/src/migrate.rs b/src/migrate.rs new file mode 100644 index 0000000000..99cd54efd5 --- /dev/null +++ b/src/migrate.rs @@ -0,0 +1,34 @@ +use std::fs; +use std::path::Path; + +use color_eyre::eyre::Result; + +use crate::{dirs, file}; + +pub fn run() -> Result<()> { + move_subdirs(&dirs::INSTALLS.join("nodejs"), &dirs::INSTALLS.join("node"))?; + move_subdirs(&dirs::INSTALLS.join("golang"), &dirs::INSTALLS.join("go"))?; + move_subdirs(&dirs::PLUGINS.join("nodejs"), &dirs::PLUGINS.join("node"))?; + move_subdirs(&dirs::PLUGINS.join("golang"), &dirs::PLUGINS.join("go"))?; + + Ok(()) +} + +fn move_subdirs(from: &Path, to: &Path) -> Result<()> { + if from.exists() { + info!("migrating {} to {}", from.display(), to.display()); + file::create_dir_all(to)?; + for f in from.read_dir()? { + let f = f?.file_name(); + let from_file = from.join(&f); + let to_file = to.join(&f); + if !to_file.exists() { + debug!("moving {} to {}", from_file.display(), to_file.display()); + fs::rename(from_file, to_file)?; + } + } + file::remove_all(from)?; + } + + Ok(()) +} diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 17d53200c6..88029685dd 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -17,7 +17,6 @@ type ToolMap = BTreeMap>; pub static CORE_PLUGINS: Lazy = Lazy::new(|| { build_core_plugins(vec![ Box::new(NodePlugin::new("node".to_string()).with_legacy_file_support()), - Box::new(NodePlugin::new("nodejs".to_string())), Box::new(PythonPlugin::new("python".to_string())), ]) }); diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index c25fcd2d9d..2d7d098664 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -85,6 +85,14 @@ pub trait Plugin: Debug + Send + Sync { } } +pub fn unalias_plugin(plugin_name: &str) -> &str { + match plugin_name { + "nodejs" => "node", + "golang" => "go", + _ => plugin_name, + } +} + pub enum PluginType { #[allow(dead_code)] Core,